Hmbown/CodeWhale · warning
first Stop
Error message
first Stop
What it means
Test assertion `manager.cancel_agent(&agent_id).expect("first Stop")` in the model-wait-cancel fan-in test at `crates/tui/src/tools/subagent/tests.rs:6587`. The test puts an agent into ModelWait state and issues the first Stop/cancel; the expect asserts cancellation of a live agent succeeds and returns its termination record. A panic here means the manager refused or failed the first cancel.
Solutions
- Print the cancel_agent error (replace expect with a descriptive panic including the Err) to see why the first Stop was rejected.
- Verify the agent was registered with the same manager and id used in cancel_agent.
- Check cancel_agent's state gating: ModelWait agents must remain cancellable; fix the state machine if it now returns an error for ModelWait.
- Re-run with the unmodified test to confirm it is a regression from a recent commit (git blame the cancel path).
Example fix
// before
let first = manager.cancel_agent(&agent_id).expect("first Stop");
// after
let first = manager.cancel_agent(&agent_id)
.unwrap_or_else(|e| panic!("first Stop of {agent_id} failed: {e:?}")); Defensive patterns
Strategy: type-guard
Validate before calling
// Before cancelling, confirm the agent is known and cancellable: assert!(manager.get_worker_record(&agent_id).is_some(), "agent must be registered before first Stop");
Try / catch
let first = manager.cancel_agent(&agent_id).unwrap_or_else(|e| panic!("first Stop failed: {e:?}")); Prevention
- Keep ModelWait and all non-terminal states cancellable in cancel_agent's gating.
- Assert registration before lifecycle calls in tests.
- Include the error payload in lifecycle-assertion panic messages.
When it happens
Trigger: `cancel_agent` returns Err for an agent it should know about — e.g. the agent was never registered with this manager (wrong SubAgentManager instance or tmp path), the id string 'agent_model_wait_cancel' mismatches, or a change to cancel_agent makes ModelWait a non-cancellable state.
Common situations: Refactors of the subagent state machine (adding states, gating cancellation by status) that forget ModelWait; test setup reordering so the manager is constructed with a different store dir than the agent was registered under.
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
- first coordination interrupt
- parent cancellation fan-in
- repeated Stop
- worker record
- worker record remains inspectable
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/7a38629112bb27a5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/subagent/tests.rs:6587
let (completion_tx, mut completion_rx) = mpsc::channel::<SubAgentCompletion>(16);
let (mailbox, mut mailbox_rx) = Mailbox::new(CancellationToken::new());
let (event_tx, mut event_rx) = mpsc::channel(8);
let mut runtime = runtime_with_depth(1, Some(completion_tx));
runtime.mailbox = Some(mailbox);
runtime.event_tx = Some(event_tx);
agent.terminal_delivery = Some(SubAgentTerminalDeliveryContext::from_runtime(&runtime));
manager.agents.insert(agent_id.clone(), agent);
manager.register_worker(make_worker_spec(&agent_id, tmp.path().to_path_buf()));
manager.record_worker_event(
&agent_id,
AgentWorkerStatus::ModelWait,
Some(SUBAGENT_MODEL_WAIT_REASON.to_string()),
Some(1),
None,
);
let first = manager.cancel_agent(&agent_id).expect("first Stop");
let second = manager.cancel_agent(&agent_id).expect("repeated Stop");
assert_eq!(first.status, SubAgentStatus::Cancelled);
assert_eq!(second.status, SubAgentStatus::Cancelled);
assert_eq!(
first
.checkpoint
.as_ref()
.map(|checkpoint| checkpoint.reason.as_str()),
Some("test_checkpoint")
);
let completion = completion_rx
.try_recv()
.expect("parent cancellation fan-in");
assert!(completion.payload.contains(r#""status":"cancelled""#));
assert!(completion_rx.try_recv().is_err());
let terminal_mail = mailbox_rxView on GitHub (pinned to 73e0f67d83)