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

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 (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 (lines 415-422), the system checks for div.upload-failure elements:


# 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, the TikTok uploader retrieves the specific error message and pushes it to the shared status queue:


# 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 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 (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 (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 (lines 707-710):


# 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, the application instantiates an EventSource connection to the backend stream:

// 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 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 and douyin_uploader/main.py.
  • Structured logging via 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, 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 and 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 (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 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 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →