{"record":{"id":"eeef62884d0a4dde","repo":"Hmbown/CodeWhale","slug":"agent-agent-id-has-no-continuable-checkpoint-to","errorCode":null,"errorMessage":"Agent {agent_id} has no continuable checkpoint to resume from (continuable={continuable}, messages={messages})","messagePattern":"Agent (.+?) has no continuable checkpoint to resume from \\(continuable=(.+?), messages=(.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":6245,"sourceCode":"            if !resumable {\n                return Err(anyhow!(\n                    \"Cannot resume agent {agent_id}: status is {} ({})\",\n                    subagent_status_name(&agent.status),\n                    policy.describe()\n                ));\n            }\n            let checkpoint = agent\n                .checkpoint\n                .as_ref()\n                .filter(|cp| cp.continuable && !cp.messages.is_empty())\n                .ok_or_else(|| {\n                    let continuable = agent.checkpoint.as_ref().is_some_and(|cp| cp.continuable);\n                    let messages = agent\n                        .checkpoint\n                        .as_ref()\n                        .map(|cp| cp.messages.len())\n                        .unwrap_or(0);\n                    anyhow!(\n                        \"Agent {agent_id} has no continuable checkpoint to resume from (continuable={continuable}, messages={messages})\"\n                    )\n                })?;\n            // Restore the interrupted child's write claim so the resumed loop\n            // stays inside the coordination ledger with the original bounded\n            // scope instead of inheriting the caller's unchecked write surface.\n            // The ledger claim is already namespaced and carries the isolation\n            // flag; both are passed through to the spawn seam.\n            let claim = self\n                .coordination\n                .write_claims\n                .iter()\n                .find(|record| record.claim.owner == agent_id)\n                .map(|record| (record.claim.clone(), record.isolated_worktree));\n            // Preserve the interrupted child's runtime posture (read_only /\n            // denied tools / shell) instead of rebuilding from the caller's\n            // role, which could widen the resumed child's authority.\n            let preserved_profile = self","sourceCodeStart":6227,"sourceCodeEnd":6263,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/mod.rs#L6227-L6263","documentation":"Resuming an interrupted sub-agent requires a stored checkpoint marked continuable. This error means the agent exists but its checkpoint is missing, non-continuable, or has no messages to replay, so the resume path fails closed rather than fabricating a fresh run.","triggerScenarios":"Calling the agent resume path (agents/resume) for an agent_id whose `agent.checkpoint` is None, or whose checkpoint has `continuable == false`, or whose checkpoint contains zero messages. The check runs before restoring the child's write claim.","commonSituations":"Resuming after the checkpoint was cleared by a completed/cancelled run; resuming a sub-agent that failed before producing any messages; double-resuming the same checkpoint; upgrading from an older session format that did not persist checkpoints.","solutions":["Inspect the agent's checkpoint state (`continuable`, `messages.len()`) in the error text and confirm whether it should be continuable; if not, spawn a new sub-agent instead of resuming.","Re-run the interrupted work as a fresh sub-agent spawn, carrying the original task prompt.","If resuming mid-workflow, cancel or clean up the stale agent entry (agents/cancel or agents/remove) and re-dispatch.","If checkpoints should persist across restarts, verify the session store is loading saved checkpoints and that no version change dropped them."],"exampleFix":"// before\nlet out = agents.resume(agent_id)?;\n\n// after\nif let Some(agent) = agents.get(&agent_id) {\n    let continuable = agent.checkpoint.as_ref().is_some_and(|cp| cp.continuable && !cp.messages.is_empty());\n    if !continuable {\n        // respawn fresh instead of resuming\n        return spawn_new_agent(task);\n    }\n}\nlet out = agents.resume(agent_id)?;","handlingStrategy":"validation","validationCode":"fn resumable(agent: &SubAgentHandle) -> bool {\n    agent.checkpoint.as_ref().is_some_and(|cp| cp.continuable && !cp.messages.is_empty())\n}\n// call only if resumable(&agent)","typeGuard":"fn continuable_checkpoint(cp: &Option<Checkpoint>) -> Option<&Checkpoint> {\n    cp.as_ref().filter(|c| c.continuable && !c.messages.is_empty())\n}","tryCatchPattern":"match agents.resume(agent_id) {\n    Err(e) if e.to_string().contains(\"no continuable checkpoint\") => spawn_fresh_agent(task),\n    other => other?,\n}","preventionTips":["Check checkpoint.continuable before issuing resume","Never assume an interrupted agent is always resumable; completed/cancelled ones are not","Persist checkpoints across restarts and verify session-store loading"],"tags":["subagent","resume","checkpoint","invalid-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}