{"record":{"id":"1b5f56bfced62653","repo":"Hmbown/CodeWhale","slug":"cannot-resume-agent-agent-id-status-is","errorCode":null,"errorMessage":"Cannot resume agent {agent_id}: status is {} ({})","messagePattern":"Cannot resume agent (.+?): status is (.+?) \\((.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":6228,"sourceCode":"            claim,\n            preserved_profile,\n            child_route,\n        ) = {\n            let agent = self\n                .agents\n                .get(&agent_id)\n                .ok_or_else(|| anyhow!(\"Agent {agent_id} not found\"))?;\n            let resumable = match policy {\n                ResumePolicy::InterruptedOnly => {\n                    matches!(agent.status, SubAgentStatus::Interrupted(_))\n                }\n                ResumePolicy::InterruptedOrCompleted => matches!(\n                    agent.status,\n                    SubAgentStatus::Interrupted(_) | SubAgentStatus::Completed\n                ),\n            };\n            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})\"","sourceCodeStart":6210,"sourceCodeEnd":6246,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/mod.rs#L6210-L6246","documentation":"Thrown by `resume_from_checkpoint_with_policy` when the agent exists but its status does not satisfy the requested `ResumePolicy`: `InterruptedOnly` requires status Interrupted, `InterruptedOrCompleted` additionally accepts Completed. The message reports the actual status and the policy description so the caller can pick the right policy.","triggerScenarios":"Calling resume with `ResumePolicy::InterruptedOnly` on a Completed (or Running/terminal) child, or with `InterruptedOrCompleted` on a Failed/Cancelled/BudgetExhausted/Running child — the status/policy mismatch fails closed.","commonSituations":"A resume script uses InterruptedOnly but the child already finished; a caller picks the wrong policy for the situation (trying to resume a cancelled child); the child's status changed from Interrupted to Completed between check and resume.","solutions":["Read the agent's status first and select the matching policy: InterruptedOnly for Interrupted, InterruptedOrCompleted to also allow Completed.","If the child is Failed/Cancelled/BudgetExhausted, do not resume — spawn a new child instead.","If the status changed between check and resume, re-fetch the status and retry with the correct policy.","Use the policy description in the message to see exactly which statuses the chosen policy accepts."],"exampleFix":"// before\nlet policy = ResumePolicy::InterruptedOnly;\nregistry.resume_from_checkpoint_with_policy(&handle, runtime, &agent_id, policy)?;\n// after\nlet policy = match registry.status_of(&agent_id) {\n    SubAgentStatus::Interrupted(_) => ResumePolicy::InterruptedOnly,\n    SubAgentStatus::Completed => ResumePolicy::InterruptedOrCompleted,\n    other => anyhow::bail!(\"agent is {:?}; cannot resume\", other),\n};\nregistry.resume_from_checkpoint_with_policy(&handle, runtime, &agent_id, policy)?;","handlingStrategy":"validation","validationCode":"let policy = match registry.status_of(agent_id) {\n    SubAgentStatus::Interrupted(_) => ResumePolicy::InterruptedOnly,\n    SubAgentStatus::Completed => ResumePolicy::InterruptedOrCompleted,\n    other => anyhow::bail!(\"status {:?} does not satisfy any resume policy\", other),\n};","typeGuard":"fn policy_allows(policy: &ResumePolicy, status: &SubAgentStatus) -> bool {\n    match policy {\n        ResumePolicy::InterruptedOnly => matches!(status, SubAgentStatus::Interrupted(_)),\n        ResumePolicy::InterruptedOrCompleted => matches!(status, SubAgentStatus::Interrupted(_) | SubAgentStatus::Completed),\n    }\n}","tryCatchPattern":"match registry.resume_from_checkpoint_with_policy(&handle, runtime, agent_id, policy) {\n    Err(e) if e.to_string().contains(\"Cannot resume agent\") => {\n        // re-read status and retry with the matching policy, or spawn a replacement\n    }\n    r => r?,\n}","preventionTips":["Derive the ResumePolicy from the child's current status instead of hardcoding it.","Remember InterruptedOnly rejects Completed children — widen the policy if finished children must resume.","Re-read the status immediately before resuming to avoid check/act races.","Treat Failed/Cancelled/BudgetExhausted as never-resumable in policy selection."],"tags":["subagent","agent-lifecycle","invalid-state-transition","checkpoint-resume","rust"],"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"}