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

  1. Check Gateway logs for the preceding 'Failed to update artifact' exception — the real cause (OSError, sandbox error) is logged there
  2. Verify filesystem permissions and free space on the artifacts root
  3. If the sandbox sync is failing, verify the sandbox provider is reachable and retry once the sandbox is healthy
  4. 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

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


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