# How Upload Errors Are Handled and Reported in social-auto-upload

> Discover how social-auto-upload handles upload errors. Learn about Playwright detection, structured logging, optional retries, and real-time SSE reporting from Python backend to Vue.js frontend.

- Repository: [Alleria/social-auto-upload](https://github.com/dreammis/social-auto-upload)
- Tags: how-to-guide
- Published: 2026-05-31

---

**Upload errors in the social-auto-upload project are detected via Playwright page automation, logged with structured emoji-enhanced messages, optionally retried through a recursive coroutine, and streamed to users in real-time via Server-Sent Events (SSE) connecting the Python backend to the Vue.js frontend.**

The `dreammis/social-auto-upload` repository automates video uploads across multiple platforms including Douyin, TikTok, Bilibili, and Xiaohongshu. When platform-specific automation fails, the system implements a standardized pipeline for upload error handling and reporting that ensures users receive immediate visual feedback while maintaining detailed logs for debugging.

## Error Detection in Platform Uploaders

Each platform-specific uploader implements detection logic to identify failure states during the upload process. In [`uploader/tencent_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/tencent_uploader/main.py) (lines 649-653), the code checks for error indicators such as missing DOM elements, specific error text like "上传失败" (upload failed), or HTTP rejection signals.

When the Playwright `page.locator()` detects an error condition, the uploader immediately delegates to the `handle_upload_error` coroutine. For example, in [`uploader/douyin_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/douyin_uploader/main.py) (lines 415-422), the system checks for `div.upload-failure` elements:

```python

# uploader/douyin_uploader/main.py

if await page.locator("div.upload-failure").count():
    douyin_logger.error(_msg("😵", "检测到上传失败，准备重试"))
    await self.handle_upload_error(page)

```

## The handle_upload_error Coroutine

Every platform uploader implements an async `handle_upload_error` method that standardizes error processing. This coroutine extracts error details from the page DOM, logs the failure, and communicates status updates to the user interface.

In [`uploader/tk_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/tk_uploader/main.py), the TikTok uploader retrieves the specific error message and pushes it to the shared status queue:

```python

# uploader/tk_uploader/main.py

async def handle_upload_error(self, page):
    tiktok_logger.info("video upload error retrying.")
    # locate the error message on the page

    err = await page.locator("div.error-msg").inner_text()
    tiktok_logger.error(f"Upload error: {err}")
    # push a status update for the front-end

    self.status_queue.put(f"Upload error: {err}")
    # optional: retry logic …

```

The logging infrastructure in [`utils/log.py`](https://github.com/dreammis/social-auto-upload/blob/main/utils/log.py) formats these entries with emoji flags and human-readable timestamps, writing simultaneously to the console and optionally to persistent log files.

## Automatic Retry Mechanism

Most uploaders attempt automatic recovery before declaring a final failure. The retry logic recursively invokes `handle_upload_error` with a limited attempt counter to prevent infinite loops.

In [`uploader/tk_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/tk_uploader/main.py) (lines 251-253), the system implements attempt tracking:

- **Attempt limit**: Hard-coded or configured maximum retries (typically 3-5 attempts)
- **Backoff strategy**: Brief delays between attempts to allow platform rate limits to reset
- **State reset**: Page reload or navigation back to the upload form between attempts

If the retry limit exhausts without success, the uploader pushes a final failure status to the queue rather than attempting further recovery.

## Status Queue and Backend SSE Streaming

The backend orchestrates user communication through a **status queue** pattern implemented in [`sau_backend.py`](https://github.com/dreammis/social-auto-upload/blob/main/sau_backend.py) (lines 386-395). Each upload request receives a dedicated queue instance that serves as the communication bridge between the async uploader and the web frontend.

When `handle_upload_error` detects a failure, it pushes formatted status strings into this queue. The backend then streams these messages via Server-Sent Events (SSE) using the `sse_stream` generator in [`sau_backend.py`](https://github.com/dreammis/social-auto-upload/blob/main/sau_backend.py) (lines 707-710):

```python

# sau_backend.py

def sse_stream(status_queue):
    while True:
        if not status_queue.empty():
            msg = status_queue.get()
            yield f"data: {msg}\n\n"

```

This creates a `text/event-stream` response that maintains a persistent connection with the browser, allowing real-time error notifications without polling overhead.

## Frontend Integration and User Feedback

The Vue.js frontend consumes the SSE endpoint to display immediate visual feedback. In [`sau_frontend/src/api/account.js`](https://github.com/dreammis/social-auto-upload/blob/main/sau_frontend/src/api/account.js), the application instantiates an `EventSource` connection to the backend stream:

```javascript
// sau_frontend/src/api/account.js
const eventSource = new EventSource('/api/upload_status?id=' + uploadId);
eventSource.onmessage = e => {
  this.uploadStatus = e.data;   // displayed in a toast / status bar
};

```

The reactive state managed in [`sau_frontend/src/stores/app.js`](https://github.com/dreammis/social-auto-upload/blob/main/sau_frontend/src/stores/app.js) binds these messages to the UI components, rendering:

- **Emoji-enhanced alerts**: Messages like "😢 登录失败" (login failure) or "😵 发现上传出错了" (upload error detected)
- **Retry notifications**: "上传错误，正在重试…" when automatic recovery initiates
- **Final status codes**: `data: 200` for success or `data: 500` for terminal failure after all retries exhaust

Because all platform uploaders utilize the identical **status-queue → SSE → frontend** pipeline, users experience consistent error reporting regardless of whether uploading to Douyin, TikTok, Kuaishou, or Bilibili.

## Summary

- **Error detection** occurs through Playwright locators checking for DOM error indicators and specific failure text in platform-specific uploaders like [`tencent_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/tencent_uploader/main.py) and [`douyin_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/douyin_uploader/main.py).
- **Structured logging** via [`utils/log.py`](https://github.com/dreammis/social-auto-upload/blob/main/utils/log.py) captures errors with emoji-enhanced formatting for both console and file outputs.
- **`handle_upload_error` coroutines** in each uploader extract error details, trigger limited automatic retries, and push status updates to a per-upload queue.
- **Real-time reporting** flows through Server-Sent Events in [`sau_backend.py`](https://github.com/dreammis/social-auto-upload/blob/main/sau_backend.py), streaming messages from the status queue to the Vue.js frontend without polling.
- **Consistent UX** across all social platforms results from the standardized queue-to-SSE pipeline, displaying toast notifications and final success/failure codes to users.

## Frequently Asked Questions

### What triggers the handle_upload_error coroutine in social-auto-upload?

The `handle_upload_error` coroutine triggers when Playwright automation detects specific failure indicators on the target platform's page. Detection occurs when locators find error message elements (e.g., `div.upload-failure` or `div.error-msg`), missing required iframes, or text containing "上传失败" (upload failed). This check happens continuously during the upload process in the main upload loops of platform-specific files like [`uploader/douyin_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/douyin_uploader/main.py) and [`uploader/tencent_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/tencent_uploader/main.py).

### How does social-auto-upload prevent infinite retry loops when uploads fail?

The uploaders implement attempt counting within the `handle_upload_error` coroutine to limit recursive retries. In files like [`uploader/tk_uploader/main.py`](https://github.com/dreammis/social-auto-upload/blob/main/uploader/tk_uploader/main.py) (lines 251-253), the code tracks retry attempts and exits the recursive loop after reaching a platform-specific threshold, typically between three to five attempts. Once exhausted, the system pushes a terminal failure status to the queue rather than continuing retry attempts.

### Can users see real-time upload errors while the automation is running?

Yes, users receive immediate visual feedback through the Server-Sent Events (SSE) pipeline. The backend `sse_stream` generator in [`sau_backend.py`](https://github.com/dreammis/social-auto-upload/blob/main/sau_backend.py) continuously pulls messages from the upload's status queue and forwards them as `data:` events. The Vue frontend listens via `EventSource` in [`sau_frontend/src/api/account.js`](https://github.com/dreammis/social-auto-upload/blob/main/sau_frontend/src/api/account.js) and displays messages in toast notifications or status bars, including specific error details and retry status updates.

### Where are upload error logs stored in the social-auto-upload system?

Error logs are handled by the centralized logger defined in [`utils/log.py`](https://github.com/dreammis/social-auto-upload/blob/main/utils/log.py), which writes structured, emoji-enhanced messages to the console by default. The logging configuration supports redirecting output to persistent files through standard Python logging handlers. Additionally, individual uploaders like the Douyin and TikTok implementations create platform-specific logger instances that tag entries with context such as account IDs and video filenames for easier debugging.