bytedance/deer-flow · error · HTTPException
Failed to update artifact
Error message
Failed to update artifact
What it means
Catch-all 500 from the artifact update route: any exception other than ConflictError and HTTPException during an artifact save (read, validation, atomic replace, or the sandbox-sync attempt) is logged with the path and thread id and re-raised as this generic 500. The route has already attempted rollback: the original content is re-synced to the sandbox if the write failed mid-flight.
Source
Thrown at backend/app/gateway/routers/artifacts.py:489
try:
if sandbox is not None:
await asyncio.to_thread(_sync_artifact_to_sandbox, sandbox, virtual_path, updated)
await asyncio.to_thread(_replace_artifact_atomically, actual_path, updated, file_stat)
except Exception:
if sandbox is not None:
try:
await asyncio.to_thread(_sync_artifact_to_sandbox, sandbox, virtual_path, current)
except Exception:
logger.exception("Failed to roll back remote artifact after artifact update failure: %s", virtual_path)
raise
except ConflictError:
raise HTTPException(status_code=409, detail="Thread has a run in flight. Save after the run finishes.") from None
except HTTPException:
raise
except Exception:
logger.exception("Failed to update artifact %s for thread %s", path, thread_id)
raise HTTPException(status_code=500, detail="Failed to update artifact") from None
finally:
if sandbox_id is not None and sandbox_provider is not None:
try:
await asyncio.to_thread(sandbox_provider.release, sandbox_id)
except Exception:
logger.warning("Failed to release sandbox after artifact update: %s", sandbox_id, exc_info=True)
content_sha256 = hashlib.sha256(updated).hexdigest()
return ArtifactUpdateResponse(
path=virtual_path,
sha256=content_sha256,
size=len(updated),
)
View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Check Gateway logs for the preceding 'Failed to update artifact' exception — the real cause (OSError, sandbox error) is logged there
- Verify filesystem permissions and free space on the artifacts root
- If the sandbox sync is failing, verify the sandbox provider is reachable and retry once the sandbox is healthy
- Re-fetch the artifact (its content should be the rolled-back original) and retry the edit after fixing the underlying issue
Defensive patterns
Strategy: try-catch
Try / catch
try {
await updateArtifact(threadId, path, content);
} catch (e) {
if (e.status === 500) {
const fresh = await getArtifact(threadId, path); // rollback means disk holds the original
reportError('Artifact save failed; server kept the previous version', { cause: e });
return;
}
throw e;
} Prevention
- Monitor Gateway logs for 'Failed to update artifact' to catch the root-cause exception early
- Keep the artifacts root writable and the sandbox provider healthy before editing files
- Retain the client-side content so a failed save can be retried after the host issue is fixed
When it happens
Trigger: PUT on an artifact where _replace_artifact_atomically fails (disk full, permission lost, path removed underneath), the mtime/size precondition inside the replace detects tampering in an unexpected way, or _sync_artifact_to_sandbox fails after a successful local write and the sandbox rollback also fails.
Common situations: Artifact directory is read-only or owned by another user after a permission change; disk exhaustion on the Gateway host; sandbox pod/container is down so the sync step throws; file deleted externally between read and write.
Related errors
- Failed to list agents: {str(e)}
- Failed to get agent: {str(e)}
- Failed to update agent: {str(e)}
- Failed to read user profile: {str(e)}
- Failed to update user profile: {str(e)}
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/ca823e15c9ef3cdf.
Report an issue: GitHub.