bytedance/deer-flow · error · HTTPException

Failed to acquire sandbox

Error message

Failed to acquire sandbox

What it means

HTTP 500 raised when the sandbox provider reports success from acquire_async(thread_id) but get(sandbox_id) then returns None — an internal inconsistency between the provider's acquire and get APIs. It means the gateway cannot obtain the sandbox handle needed to sync uploaded files into the thread's sandbox.

Source

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

    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:
            raise HTTPException(status_code=500, detail="Failed to acquire sandbox")
    auto_convert_documents = _auto_convert_documents_enabled(config)

    for file in files:
        if not file.filename:
            continue

        try:
            original_filename = normalize_filename(file.filename)
            safe_filename = claim_unique_filename(original_filename, seen_filenames)
        except ValueError:
            logger.warning(f"Skipping file with unsafe filename: {file.filename!r}")
            continue

        try:
            file_path, file_size, total_size = await _write_upload_file_with_limits(
                file,
                uploads_dir=uploads_dir,
                display_filename=safe_filename,

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Retry the upload once — transient races between acquire and get often clear.
  2. Check sandbox provider logs/health (container runtime, provisioner on port 8002 if configured) for crashes or evictions.
  3. If running a custom sandbox provider, ensure acquire_async registers the sandbox so a subsequent get(sandbox_id) succeeds.
  4. As a workaround, switch the deployment to a sandbox provider that uses thread data mounts (sync_to_sandbox becomes false and this path is skipped).
Defensive patterns

Strategy: retry

Try / catch

catch 500 with detail 'Failed to acquire sandbox'; retry the upload once after a short delay; escalate to the operator if it repeats.

Prevention

When it happens

Trigger: Only on deployments whose sandbox provider uses file syncing (i.e. _uses_thread_data_mounts is false): acquire_async returns an id, but the corresponding sandbox record is missing/expired by the time get() is called.

Common situations: Sandbox registry TTL expiring between acquire and get; a custom sandbox provider with a bug where acquire does not register the sandbox; sandbox backend (container/K8s) crash or eviction mid-request.

Related errors


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