{"record":{"id":"65bb358e50802978","repo":"bytedance/deer-flow","slug":"artifact-not-found-path","errorCode":null,"errorMessage":"Artifact not found: {path}","messagePattern":"Artifact not found: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"error","filePath":"backend/app/gateway/routers/artifacts.py","lineNumber":81,"sourceCode":"        user_id=user_id,\n    ):\n        yield\n\n\ndef _normalize_editable_artifact_path(path: str) -> str:\n    stripped = path.lstrip(\"/\")\n    if not stripped.startswith(_EDITABLE_OUTPUTS_PREFIX):\n        raise HTTPException(status_code=400, detail=\"Only files in /mnt/user-data/outputs can be edited\")\n    if \".skill/\" in stripped or stripped.endswith(\".skill\"):\n        raise HTTPException(status_code=415, detail=\"Skill archives cannot be edited in the artifacts panel\")\n    return f\"/{stripped}\"\n\n\ndef _load_editable_artifact(actual_path: Path, path: str, expected_sha256: str) -> tuple[bytes, os.stat_result]:\n    try:\n        file_stat = os.lstat(actual_path)\n    except FileNotFoundError:\n        raise HTTPException(status_code=404, detail=f\"Artifact not found: {path}\") from None\n    if stat.S_ISLNK(file_stat.st_mode):\n        raise HTTPException(status_code=415, detail=\"Symlinked artifacts cannot be edited\")\n    if not stat.S_ISREG(file_stat.st_mode):\n        raise HTTPException(status_code=400, detail=f\"Path is not a file: {path}\")\n    if file_stat.st_size > MAX_EDITABLE_ARTIFACT_BYTES:\n        raise HTTPException(status_code=413, detail=\"Artifact is too large to edit\")\n\n    current = actual_path.read_bytes()\n    if len(current) > MAX_EDITABLE_ARTIFACT_BYTES:\n        raise HTTPException(status_code=413, detail=\"Artifact is too large to edit\")\n    if b\"\\x00\" in current:\n        raise HTTPException(status_code=415, detail=\"Binary artifacts cannot be edited\")\n    try:\n        current.decode(\"utf-8\")\n    except UnicodeDecodeError:\n        raise HTTPException(status_code=415, detail=\"Only UTF-8 text artifacts can be edited\") from None\n\n    current_sha256 = hashlib.sha256(current).hexdigest()","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/artifacts.py#L63-L99","documentation":"HTTP 404 from _load_editable_artifact: os.lstat on the resolved actual path raised FileNotFoundError, meaning the artifact existed in metadata (the client had a path and sha256) but no longer exists on disk at edit-save time. Uses lstat specifically so a dangling symlink also lands here as absent.","triggerScenarios":"PUT edit-artifact for a file deleted since it was opened — the sandbox removed it, the run cleaned up outputs, another editor/session deleted it, or the thread's output dir was recreated.","commonSituations":"Editing in one tab while a re-run regenerates or removes outputs, stale editor sessions after a thread run finished and cleaned up, or file deleted by the agent mid-conversation.","solutions":["Re-fetch the artifact list (GET artifacts) to confirm the file still exists; if gone, discard the local edit buffer","If the file should exist, check whether the producing run re-executed and wrote it under a different name/path","Handle 404 by reopening the editor rather than retrying the same PUT"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Confirm the file still exists before attempting the save\narts = await client.get(f\"/api/threads/{tid}/artifacts\")\nexisting = {a[\"path\"] for a in arts.json().get(\"artifacts\", [])}\nif path not in existing:\n    raise FileNotFoundError(f\"{path} disappeared; reopen editor\")","typeGuard":null,"tryCatchPattern":"try:\n    await client.put(EDIT_URL, json=payload)\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 404:\n        # file vanished since open — reload, do not retry blindly\n        refresh_artifact_list()\n    else:\n        raise","preventionTips":["Refresh artifact listings when a run finishes before allowing edits","Disable the save button for artifacts that no longer appear in the listing","Prefer reopening the file over retrying a 404 save"],"tags":["api","artifacts","not-found","http-404","concurrency"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}