bytedance/deer-flow · error · HTTPException

str(e)

Error message

str(e)

What it means

HTTP 400 raised when ensure_uploads_dir fails with a ValueError while preparing the thread's uploads directory (e.g. the thread_id does not resolve to a valid directory path). The raw exception text is surfaced as the detail. It fires before any file is written, so the request is rejected atomically.

Source

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

async def upload_files(
    thread_id: ThreadId,
    request: Request,
    files: list[UploadFile] = File(...),
    config: AppConfig = Depends(get_config),
) -> UploadResponse:
    """Upload multiple files to a thread's uploads directory."""
    if not files:
        raise HTTPException(status_code=400, detail="No files provided")

    limits = _get_upload_limits(config)
    if len(files) > limits.max_files:
        raise HTTPException(status_code=413, detail=f"Too many files: maximum is {limits.max_files}")

    try:
        effective_user_id = get_effective_user_id()
        uploads_dir = await run_file_io(ensure_uploads_dir, thread_id, user_id=effective_user_id)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    sandbox_uploads = uploads_dir
    uploaded_files = []
    written_paths = []
    sandbox_sync_targets = []
    skipped_files = []
    total_size = 0
    # Track filenames within this request so duplicate form parts do not
    # silently truncate each other. Existing uploads keep the historical
    # overwrite behavior for a single replacement upload.
    seen_filenames: set[str] = set()

    sandbox_provider = get_sandbox_provider()
    sync_to_sandbox = not _uses_thread_data_mounts(sandbox_provider)
    sandbox = None
    if sync_to_sandbox:
        sandbox_id = await sandbox_provider.acquire_async(thread_id, user_id=effective_user_id)
        sandbox = sandbox_provider.get(sandbox_id)
        if sandbox is None:

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Verify the thread exists via the threads API before uploading and use the exact id it returned.
  2. Inspect the returned detail message — it is the ValueError text from ensure_uploads_dir and names the concrete problem (invalid id, unresolvable path).
  3. Re-create the thread and retry the upload if the thread was deleted.
Defensive patterns

Strategy: validation

Validate before calling

const thread = await fetch(`/api/threads/${encodeURIComponent(tid)}`).then(r => r.ok ? r.json() : null);
if (!thread) throw new Error('Thread does not exist');

Try / catch

catch 400 on upload; surface detail text (it names the invalid id/path) and stop — do not blind-retry.

Prevention

When it happens

Trigger: Uploading to a thread whose id is malformed or cannot be mapped to a storage path (ensure_uploads_dir raises ValueError); uploading to a thread that was deleted or whose per-user directory cannot be created/resolved.

Common situations: Client generates a thread id locally instead of using one returned by the threads API; a thread was deleted while an upload was in flight; user-context (effective_user_id) resolves to a path segment the storage layer rejects.

Related errors


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