{"record":{"id":"2dba89db9b77bed9","repo":"bytedance/deer-flow","slug":"checkpoint-is-missing-checkpoint-id","errorCode":null,"errorMessage":"Checkpoint is missing checkpoint_id","messagePattern":"Checkpoint is missing checkpoint_id","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"error","filePath":"backend/app/gateway/routers/thread_runs.py","lineNumber":373,"sourceCode":"\ndef _checkpoint_messages(snapshot: Any) -> list[Any]:\n    return checkpoint_messages(snapshot)\n\n\ndef _checkpoint_values(snapshot: Any) -> dict[str, Any]:\n    values = getattr(snapshot, \"values\", None)\n    return dict(values) if isinstance(values, dict) else {}\n\n\ndef _checkpoint_configurable(checkpoint_tuple: Any) -> dict[str, Any]:\n    return checkpoint_configurable(checkpoint_tuple)\n\n\ndef _checkpoint_response(checkpoint_tuple: Any) -> dict[str, Any]:\n    configurable = _checkpoint_configurable(checkpoint_tuple)\n    checkpoint_id = configurable.get(\"checkpoint_id\")\n    if not checkpoint_id:\n        raise HTTPException(status_code=409, detail=\"Checkpoint is missing checkpoint_id\")\n    return {\n        \"checkpoint_ns\": str(configurable.get(\"checkpoint_ns\") or \"\"),\n        \"checkpoint_id\": str(checkpoint_id),\n        \"checkpoint_map\": configurable.get(\"checkpoint_map\"),\n    }\n\n\ndef _clean_human_message_for_regenerate(message: Any) -> dict[str, Any]:\n    additional_kwargs = _message_additional_kwargs(message)\n    content = get_original_user_content_text(_message_content(message), additional_kwargs)\n    additional_kwargs.pop(ORIGINAL_USER_CONTENT_KEY, None)\n    additional_kwargs.pop(\"hide_from_ui\", None)\n\n    clean_message: dict[str, Any] = {\n        \"type\": \"human\",\n        \"content\": [{\"type\": \"text\", \"text\": content}],\n        \"additional_kwargs\": additional_kwargs,\n    }","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/thread_runs.py#L355-L391","documentation":"Raised by _checkpoint_response (HTTP 409) when a LangGraph checkpoint tuple's configurable dict has no 'checkpoint_id'. The router builds the regenerate checkpoint response from checkpoint_configurable(); a checkpoint without an id cannot be addressed for replay, so the operation is refused. It indicates the checkpoint tuple passed in is empty (e.g. a thread with no history) or came from a malformed/degenerate checkpoint write.","triggerScenarios":"Calling the regenerate prepare endpoint on a thread whose latest/base checkpoint tuple resolves to None or has an empty configurable; a checkpoint store that returns tuples without thread_ts/checkpoint_id; replaying against a thread whose checkpoints were pruned mid-operation.","commonSituations":"Regenerating immediately after thread creation before any run checkpointed; a custom checkpointer that drops configurable fields; checkpoint DB rows deleted between the history scan and the aget call; older checkpoints written by a different LangGraph version with a different configurable schema.","solutions":["Verify the thread actually has runs: GET the thread's state/run history and confirm at least one completed run exists before regenerating.","Inspect the checkpoint store directly (e.g. the checkpoints table / checkpointer list) for the thread_id to confirm checkpoint rows carry a valid checkpoint_id.","If a custom checkpointer is used, ensure put() persists configurable['checkpoint_id'] and aget() returns full tuples.","Re-run the conversation once so a fresh, well-formed checkpoint is written, then retry regenerate."],"exampleFix":"// before\nconst res = await fetch(`/api/thread/${threadId}/runs/regenerate-prepare`, {method: 'POST'});\n// after\nconst state = await fetch(`/api/threads/${threadId}/state`).then(r => r.json());\nif (!state.checkpoint?.checkpoint_id) throw new Error('Thread has no addressable checkpoint yet');\nconst res = await fetch(`/api/thread/${threadId}/runs/regenerate-prepare`, {method: 'POST'});","handlingStrategy":"validation","validationCode":"const state = await getThreadState(threadId);\nif (!state?.checkpoint?.checkpoint_id) {\n  throw new Error('Thread has no addressable checkpoint; run a message first');\n}","typeGuard":"function hasAddressableCheckpoint(state: unknown): state is { checkpoint: { checkpoint_id: string } } {\n  return !!state && typeof state === 'object'\n    && typeof (state as any).checkpoint?.checkpoint_id === 'string'\n    && (state as any).checkpoint.checkpoint_id.length > 0;\n}","tryCatchPattern":"try { await regeneratePrepare(threadId, messageId); } catch (e) { if (e.status === 409 && /missing checkpoint_id/.test(e.detail)) { showInfo('Nothing to regenerate yet'); } else { throw e; } }","preventionTips":["Only offer regenerate after a completed run","Fetch thread state and require checkpoint_id before showing regenerate UI"],"tags":["checkpoint","langgraph","regenerate","http-409"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}