bytedance/deer-flow · warning · HTTPException

Too many files: maximum is {limits.max_files}

Error message

Too many files: maximum is {limits.max_files}

What it means

Raised by the multi-file upload endpoint when the number of files in a single multipart request exceeds the configured limit (limits.max_files from the gateway's upload limits config). The endpoint counts form file parts before writing anything and rejects the whole request with HTTP 413 so no partial uploads occur. It exists to bound request handling cost per call.

Source

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

    except Exception:
        return False


@router.post("", response_model=UploadResponse)
@require_permission("threads", "write", owner_check=True, require_existing=False)
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()

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Split the upload into batches of at most limits.max_files files per request.
  2. Check GET /threads/{thread_id}/uploads/limits (the endpoint that returns _get_upload_limits) before uploading and chunk accordingly.
  3. If the use case legitimately needs more files per call, raise the max_files upload limit in the gateway config and restart.

Example fix

// before
const form = new FormData();
allFiles.forEach(f => form.append('files', f));
await fetch(`/api/threads/${tid}/uploads`, {method:'POST', body: form});

// after
const limits = await fetch(`/api/threads/${tid}/uploads/limits`).then(r=>r.json());
for (const batch of chunk(allFiles, limits.max_files)) {
  const form = new FormData();
  batch.forEach(f => form.append('files', f));
  await fetch(`/api/threads/${tid}/uploads`, {method:'POST', body: form});
}
Defensive patterns

Strategy: validation

Validate before calling

const limits = await fetch(`/api/threads/${tid}/uploads/limits`).then(r => r.json());
const batches = chunk(files, limits.max_files);
// upload batches sequentially

Prevention

When it happens

Trigger: POST multipart/form-data to /threads/{thread_id}/uploads with more `files` parts than config.max_files (default set by the gateway's upload limits). E.g. attaching 11 files when max_files is 10.

Common situations: Bulk-attaching many documents in a chat UI; lowering max_files in config.yaml after clients were already batching large uploads; automated scripts that glob a directory and upload everything at once.

Related errors


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