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.
Solutions
- Retry the upload once — transient races between acquire and get often clear.
- Check sandbox provider logs/health (container runtime, provisioner on port 8002 if configured) for crashes or evictions.
- If running a custom sandbox provider, ensure acquire_async registers the sandbox so a subsequent get(sandbox_id) succeeds.
- 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
- Monitor sandbox provider health (container runtime / provisioner) alongside the gateway.
- Prefer sandbox providers using thread data mounts, which skip the acquire/sync path entirely.
- Keep sandbox registry TTLs comfortably longer than the longest upload request.
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
- Failed to complete Lark authorization.
- Failed to delete
- Failed to update artifact
- Failed to upload
- Failed to clear memory data.
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/2afb7fe3692787ec.
Report an issue: GitHub.
Appendix: 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)