Hmbown/CodeWhale · error

Cannot resume agent : status is ( )

Error message

Cannot resume agent {agent_id}: status is {} ({})

What it means

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.

Solutions

  1. Read the agent's status first and select the matching policy: InterruptedOnly for Interrupted, InterruptedOrCompleted to also allow Completed.
  2. If the child is Failed/Cancelled/BudgetExhausted, do not resume — spawn a new child instead.
  3. If the status changed between check and resume, re-fetch the status and retry with the correct policy.
  4. Use the policy description in the message to see exactly which statuses the chosen policy accepts.

Example fix

// before
let policy = ResumePolicy::InterruptedOnly;
registry.resume_from_checkpoint_with_policy(&handle, runtime, &agent_id, policy)?;
// after
let policy = match registry.status_of(&agent_id) {
    SubAgentStatus::Interrupted(_) => ResumePolicy::InterruptedOnly,
    SubAgentStatus::Completed => ResumePolicy::InterruptedOrCompleted,
    other => anyhow::bail!("agent is {:?}; cannot resume", other),
};
registry.resume_from_checkpoint_with_policy(&handle, runtime, &agent_id, policy)?;
Defensive patterns

Strategy: validation

Validate before calling

let policy = match registry.status_of(agent_id) {
    SubAgentStatus::Interrupted(_) => ResumePolicy::InterruptedOnly,
    SubAgentStatus::Completed => ResumePolicy::InterruptedOrCompleted,
    other => anyhow::bail!("status {:?} does not satisfy any resume policy", other),
};

Type guard

fn policy_allows(policy: &ResumePolicy, status: &SubAgentStatus) -> bool {
    match policy {
        ResumePolicy::InterruptedOnly => matches!(status, SubAgentStatus::Interrupted(_)),
        ResumePolicy::InterruptedOrCompleted => matches!(status, SubAgentStatus::Interrupted(_) | SubAgentStatus::Completed),
    }
}

Try / catch

match registry.resume_from_checkpoint_with_policy(&handle, runtime, agent_id, policy) {
    Err(e) if e.to_string().contains("Cannot resume agent") => {
        // re-read status and retry with the matching policy, or spawn a replacement
    }
    r => r?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/1b5f56bfced62653. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/subagent/mod.rs:6228

            claim,
            preserved_profile,
            child_route,
        ) = {
            let agent = self
                .agents
                .get(&agent_id)
                .ok_or_else(|| anyhow!("Agent {agent_id} not found"))?;
            let resumable = match policy {
                ResumePolicy::InterruptedOnly => {
                    matches!(agent.status, SubAgentStatus::Interrupted(_))
                }
                ResumePolicy::InterruptedOrCompleted => matches!(
                    agent.status,
                    SubAgentStatus::Interrupted(_) | SubAgentStatus::Completed
                ),
            };
            if !resumable {
                return Err(anyhow!(
                    "Cannot resume agent {agent_id}: status is {} ({})",
                    subagent_status_name(&agent.status),
                    policy.describe()
                ));
            }
            let checkpoint = agent
                .checkpoint
                .as_ref()
                .filter(|cp| cp.continuable && !cp.messages.is_empty())
                .ok_or_else(|| {
                    let continuable = agent.checkpoint.as_ref().is_some_and(|cp| cp.continuable);
                    let messages = agent
                        .checkpoint
                        .as_ref()
                        .map(|cp| cp.messages.len())
                        .unwrap_or(0);
                    anyhow!(
                        "Agent {agent_id} has no continuable checkpoint to resume from (continuable={continuable}, messages={messages})"

View on GitHub (pinned to 73e0f67d83)