{"record":{"id":"dd72879e09b6e21a","repo":"bytedance/deer-flow","slug":"run-run-id-not-found-dd7287","errorCode":null,"errorMessage":"Run {run_id} not found","messagePattern":"Run (.+?) not found","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"info","filePath":"backend/app/gateway/routers/runs.py","lineNumber":102,"sourceCode":"            if snapshot_config.get(\"configurable\", {}).get(\"checkpoint_id\"):\n                return serialize_channel_values_for_api(snapshot.values)\n        except Exception:\n            logger.exception(\"Failed to fetch final state for run %s\", record.run_id)\n\n    return {\"status\": record.status.value, \"error\": record.error}\n\n\n# ---------------------------------------------------------------------------\n# Run-scoped read endpoints\n# ---------------------------------------------------------------------------\n\n\nasync def _resolve_run(run_id: str, request: Request) -> dict:\n    \"\"\"Fetch run by run_id with user ownership check. Raises 404 if not found.\"\"\"\n    run_store = get_run_store(request)\n    record = await run_store.get(run_id)  # user_id=AUTO filters by contextvar\n    if record is None:\n        raise HTTPException(status_code=404, detail=f\"Run {run_id} not found\")\n    return record\n\n\n@router.get(\"/{run_id}/messages\")\n@require_permission(\"runs\", \"read\")\nasync def run_messages(\n    run_id: str,\n    request: Request,\n    limit: int = Query(default=50, le=200, ge=1),\n    before_seq: int | None = Query(default=None, ge=1),\n    after_seq: int | None = Query(default=None, ge=1),\n) -> dict:\n    \"\"\"Return paginated messages for a run (cursor-based).\n\n    Pagination:\n    - after_seq: messages with seq > after_seq (forward)\n    - before_seq: messages with seq < before_seq (backward)\n    - neither: latest messages","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/runs.py#L84-L120","documentation":"Raised as HTTP 404 from _resolve_run by every run-scoped read endpoint (e.g. GET /api/runs/{run_id}/messages) when run_store.get(run_id) returns None. The lookup is filtered by the requesting user's contextvar, so a run owned by someone else is indistinguishable from a nonexistent run.","triggerScenarios":"GET /api/runs/{run_id}/messages (or sibling run endpoints) with a deleted run id, a typo'd id, or a valid id created under a different authenticated user.","commonSituations":"Polling a run after it was pruned/expired from the run store; sharing run ids between accounts; frontend retaining a stale run id after thread deletion.","solutions":["List the user's runs via the runs collection endpoint and confirm the run id still exists.","Verify the request carries the same authentication as the one that created the run (ownership is enforced silently).","If runs are pruned by retention, re-initiate the run instead of polling the old id."],"exampleFix":"// before\nconst res = await fetch(`/api/runs/${runId}/messages`);\nif (!res.ok) throw new Error('failed');\n// after\nconst res = await fetch(`/api/runs/${runId}/messages`);\nif (res.status === 404) { stopPolling(); return; }","handlingStrategy":"try-catch","validationCode":"runs = requests.get(f\"{BASE}/api/runs\", headers=auth).json()\nrun_ids = {r[\"id\"] for r in runs.get(\"runs\", runs if isinstance(runs, list) else [])}\nif run_id not in run_ids:\n    stop_polling(run_id)","typeGuard":"def is_existing_run(rid: str, owned: set[str]) -> bool:\n    return rid in owned","tryCatchPattern":"resp = requests.get(f\"{BASE}/api/runs/{run_id}/messages\", headers=auth)\nif resp.status_code == 404:\n    stop_polling(run_id)   # gone or not ours — terminal state\nelse:\n    resp.raise_for_status()","preventionTips":["Stop polling on the first 404; it never transitions back.","Send the same auth identity that created the run.","Persist run ids together with the auth principal that produced them."],"tags":["runs","http-404","ownership"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}