{"record":{"id":"ca823e15c9ef3cdf","repo":"bytedance/deer-flow","slug":"failed-to-update-artifact","errorCode":null,"errorMessage":"Failed to update artifact","messagePattern":"Failed to update artifact","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"backend/app/gateway/routers/artifacts.py","lineNumber":489,"sourceCode":"\n            try:\n                if sandbox is not None:\n                    await asyncio.to_thread(_sync_artifact_to_sandbox, sandbox, virtual_path, updated)\n                await asyncio.to_thread(_replace_artifact_atomically, actual_path, updated, file_stat)\n            except Exception:\n                if sandbox is not None:\n                    try:\n                        await asyncio.to_thread(_sync_artifact_to_sandbox, sandbox, virtual_path, current)\n                    except Exception:\n                        logger.exception(\"Failed to roll back remote artifact after artifact update failure: %s\", virtual_path)\n                raise\n    except ConflictError:\n        raise HTTPException(status_code=409, detail=\"Thread has a run in flight. Save after the run finishes.\") from None\n    except HTTPException:\n        raise\n    except Exception:\n        logger.exception(\"Failed to update artifact %s for thread %s\", path, thread_id)\n        raise HTTPException(status_code=500, detail=\"Failed to update artifact\") from None\n    finally:\n        if sandbox_id is not None and sandbox_provider is not None:\n            try:\n                await asyncio.to_thread(sandbox_provider.release, sandbox_id)\n            except Exception:\n                logger.warning(\"Failed to release sandbox after artifact update: %s\", sandbox_id, exc_info=True)\n\n    content_sha256 = hashlib.sha256(updated).hexdigest()\n    return ArtifactUpdateResponse(\n        path=virtual_path,\n        sha256=content_sha256,\n        size=len(updated),\n    )\n","sourceCodeStart":471,"sourceCodeEnd":503,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/artifacts.py#L471-L503","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await updateArtifact(threadId, path, content);\n} catch (e) {\n  if (e.status === 500) {\n    const fresh = await getArtifact(threadId, path); // rollback means disk holds the original\n    reportError('Artifact save failed; server kept the previous version', { cause: e });\n    return;\n  }\n  throw e;\n}","preventionTips":["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"],"tags":["artifacts","http-500","filesystem","sandbox","rollback"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}