{"record":{"id":"0f942d7e54b58151","repo":"bytedance/deer-flow","slug":"checkpoint-thread-id-does-not-match-request-thread","errorCode":null,"errorMessage":"checkpoint thread_id does not match request thread_id","messagePattern":"checkpoint thread_id does not match request thread_id","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"backend/app/gateway/services.py","lineNumber":947,"sourceCode":"async def apply_checkpoint_to_run_config(\n    config: dict[str, Any],\n    *,\n    body: Any,\n    thread_id: str,\n    request: Request,\n) -> None:\n    \"\"\"Validate an optional run checkpoint and attach it to RunnableConfig.\"\"\"\n    checkpoint = getattr(body, \"checkpoint\", None)\n    checkpoint_id = getattr(body, \"checkpoint_id\", None)\n    checkpoint_ns = \"\"\n    checkpoint_map = None\n\n    if checkpoint:\n        if not isinstance(checkpoint, Mapping):\n            raise HTTPException(status_code=400, detail=\"checkpoint must be an object\")\n        checkpoint_thread_id = checkpoint.get(\"thread_id\")\n        if checkpoint_thread_id is not None and str(checkpoint_thread_id) != thread_id:\n            raise HTTPException(status_code=400, detail=\"checkpoint thread_id does not match request thread_id\")\n        raw_checkpoint_id = checkpoint.get(\"checkpoint_id\")\n        if raw_checkpoint_id:\n            checkpoint_id = str(raw_checkpoint_id)\n        raw_checkpoint_ns = checkpoint.get(\"checkpoint_ns\")\n        if raw_checkpoint_ns is not None:\n            checkpoint_ns = str(raw_checkpoint_ns)\n        checkpoint_map = checkpoint.get(\"checkpoint_map\")\n\n    if not checkpoint_id:\n        return\n\n    read_config: dict[str, Any] = {\n        \"configurable\": {\n            \"thread_id\": thread_id,\n            \"checkpoint_ns\": checkpoint_ns,\n            \"checkpoint_id\": str(checkpoint_id),\n        }\n    }","sourceCodeStart":929,"sourceCodeEnd":965,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/services.py#L929-L965","documentation":"HTTP 400 raised when the checkpoint object's thread_id differs from the thread_id in the request URL/body. Since checkpoints belong to exactly one thread, a mismatch means the client is pointing a run at another thread's checkpoint; the gateway refuses rather than cross-read state.","triggerScenarios":"POST /threads/{thread_id}/runs with a checkpoint dict whose \"thread_id\" key names a different thread.","commonSituations":"Client-side thread switching that reuses a cached checkpoint object from a previous thread; copy-pasting an example payload from another thread; ids confused between UI conversations.","solutions":["Drop the thread_id key from the checkpoint object (it is optional), or set it to the same thread as the request.","Fetch the checkpoint list for the target thread and use checkpoints from there only."],"exampleFix":"# before\nPOST /threads/t2/runs  body: {\"checkpoint\": {\"thread_id\": \"t1\", \"checkpoint_id\": \"cp1\"}, ...}\n\n# after\nPOST /threads/t2/runs  body: {\"checkpoint\": {\"thread_id\": \"t2\", \"checkpoint_id\": \"cp1\"}, ...}","handlingStrategy":"validation","validationCode":"if (payload.checkpoint?.thread_id != null && payload.checkpoint.thread_id !== tid) {\n  delete payload.checkpoint.thread_id; // or fail fast client-side\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store checkpoints keyed by thread and never reuse a checkpoint object across threads.","Omit the optional thread_id inside checkpoint unless you can guarantee it matches."],"tags":["runs","http-400","checkpoints","thread-id"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}