bytedance/deer-flow · error · HTTPException

Failed to upload {file.filename}: {str(e)}

Error message

Failed to upload {file.filename}: {str(e)}

What it means

HTTP 500 raised when an unexpected (non-HTTP, non-UnsafeUploadPath) exception escapes while processing one file in a multi-file upload. The gateway cleans up all files already written in this request (written_paths) before failing, so the upload is atomic. The detail includes the original exception text for the offending file.

Source

Thrown at backend/app/gateway/routers/uploads.py:419

                else:
                    # Conversion failed and wrote nothing, so release the claim;
                    # holding it would rename a later same-stem upload against
                    # a name nothing occupies.
                    seen_filenames.discard(unique_md_name)

            uploaded_files.append(file_info)

        except HTTPException as e:
            await run_file_io(_cleanup_uploaded_paths, written_paths)
            raise e
        except UnsafeUploadPathError as e:
            logger.warning("Skipping upload with unsafe destination %s: %s", file.filename, e)
            skipped_files.append(safe_filename)
            continue
        except Exception as e:
            logger.error(f"Failed to upload {file.filename}: {e}")
            await run_file_io(_cleanup_uploaded_paths, written_paths)
            raise HTTPException(status_code=500, detail=f"Failed to upload {file.filename}: {str(e)}")

    # Uploaded files are created with 0o600 permissions (owner read/write only).
    # In Docker sandbox deployments the gateway writes as root but the sandbox
    # process runs as a non-root user (typically UID 1000).  Without group/other
    # read bits the sandbox cannot access the files — whether the uploads
    # directory is bind-mounted into the container or synced via
    # sandbox.update_file.  Always add group/other read bits so every sandbox
    # configuration can read the uploaded content.
    await run_file_io(_make_uploaded_paths_sandbox_readable, written_paths)

    if sync_to_sandbox:
        for file_path, virtual_path in sandbox_sync_targets:
            await run_file_io(_sync_upload_to_sandbox, sandbox, file_path, virtual_path)

    message = f"Successfully uploaded {len(uploaded_files)} file(s)"
    if skipped_files:
        message += f"; skipped {len(skipped_files)} unsafe file(s)"

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Read the {str(e)} portion of the detail and the gateway log line 'Failed to upload <filename>' — it names the actual cause (OSError, ENOSPC, EACCES, converter error).
  2. Fix the underlying filesystem issue: free disk space, correct ownership/permissions on the thread uploads directory.
  3. If the error comes from auto-convert, disable uploads.auto_convert_documents in config or install the required converter, then retry.
  4. Retry the upload after fixing — cleanup already removed partial writes, so the thread is in a clean state.
Defensive patterns

Strategy: try-catch

Try / catch

catch 500 from the upload endpoint; parse detail for the per-file cause; the gateway already cleaned partial writes, so after fixing the cause a plain retry is safe.

Prevention

When it happens

Trigger: Any per-file I/O or processing failure during the upload loop: disk full, permission denied writing to the uploads dir, failure in the auto-convert-documents step, or sandbox file-sync errors raised inside the loop.

Common situations: Gateway container out of disk or inode-exhausted; uploads volume mounted read-only or owned by the wrong user; document conversion subprocess missing its binary; a filesystem watchdog/AV scanner locking files mid-write.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/55f282bc2d88d07b. Report an issue: GitHub.