Hmbown/CodeWhale · error
sub-agent task must not park waiting for checkpoint input
Error message
sub-agent task must not park waiting for checkpoint input
What it means
Panic from `.expect("sub-agent task must not park waiting for checkpoint input")`: the outer tokio timeout fired because task_handle did not complete within 5 seconds. The test pins that a needs-input interruption after an API timeout must NOT block on checkpoint continuation; parking here is the regression.
Solutions
- Ensure the needs-input/interrupted path completes the task instead of awaiting checkpoint continuation
- Check no new wait was added around task_handle's inner join after interruption
- Confirm retries cap at SUBAGENT_API_TIMEOUT_MAX_RETRIES + 1 attempts and then return
- Raise the outer timeout only if retries legitimately exceed 5s; otherwise fix the parking
Example fix
// before
.await.expect("sub-agent task must not park waiting for checkpoint input");
// after
.await.unwrap_or_else(|_| panic!("task parked after needs-input; still running after 5s")); Defensive patterns
Strategy: try-catch
Try / catch
tokio::time::timeout(Duration::from_secs(5), task_handle)
.await
.unwrap_or_else(|_| panic!("sub-agent parked waiting for checkpoint input")); Prevention
- Keep needs-input (timeout) and user-checkpoint paths as distinct code paths
- Add watchdog assertions wherever a task may wait on a channel
- Never await continuation input on the automatic-retry path
When it happens
Trigger: The sub-agent task, upon receiving a needs-input interruption from the API timeout, awaits checkpoint input (e.g., joins a continuation channel) instead of exhausting SUBAGENT_API_TIMEOUT_MAX_RETRIES and finishing.
Common situations: A change that routes timeout interruptions into the checkpoint-parking path used for genuine user checkpoints; unbounded retry or wait added around the needs-input branch; task deadlock on an unanswered input channel.
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
- API timeout should publish an Interrupted mailbox lifecycle…
- first timed-out API attempt should reach the test server
- sub-agent task should finish
- timeout should preserve checkpoint
- Agent has no continuable checkpoint to resume from…
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/01e10ed12ca92707.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/subagent/tests.rs:9015
{
return (id, reason);
}
}
tokio::time::sleep(Duration::from_millis(10)).await;
}
})
.await
.expect("API timeout should publish an Interrupted mailbox lifecycle event");
assert_eq!(interrupted_envelope.0, agent_id);
assert!(
interrupted_envelope.1.contains("API call timed out"),
"reason should carry the timeout context: {}",
interrupted_envelope.1
);
tokio::time::timeout(Duration::from_secs(5), task_handle)
.await
.expect("sub-agent task must not park waiting for checkpoint input")
.expect("sub-agent task should finish");
assert_eq!(
calls.load(Ordering::SeqCst),
SUBAGENT_API_TIMEOUT_MAX_RETRIES.saturating_add(1) as usize,
"needs-input interruption must not park for continuation; the API call \
is retried up to the timeout-retry budget, then stops"
);
let interrupted = {
let manager = manager.read().await;
manager
.get_result(&agent_id)
.expect("agent should stay registered")
};
assert!(matches!(interrupted.status, SubAgentStatus::Interrupted(_)));
let checkpoint = interrupted
.checkpoint
.as_ref()View on GitHub (pinned to 433685b202)