{"record":{"id":"8763007b2328e61c","repo":"Hmbown/CodeWhale","slug":"api-timeout-should-publish-an-interrupted-mailbox-lifecycle","errorCode":null,"errorMessage":"API timeout should publish an Interrupted mailbox lifecycle event","messagePattern":"API timeout should publish an Interrupted mailbox lifecycle event","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/tests.rs","lineNumber":9005,"sourceCode":"    .await\n    .expect(\"first timed-out API attempt should reach the test server\");\n\n    let interrupted_envelope = tokio::time::timeout(Duration::from_secs(5), async {\n        loop {\n            for env in mailbox_rx.drain() {\n                if let MailboxMessage::Interrupted {\n                    agent_id: id,\n                    reason,\n                } = env.message\n                {\n                    return (id, reason);\n                }\n            }\n            tokio::time::sleep(Duration::from_millis(10)).await;\n        }\n    })\n    .await\n    .expect(\"API timeout should publish an Interrupted mailbox lifecycle event\");\n    assert_eq!(interrupted_envelope.0, agent_id);\n    assert!(\n        interrupted_envelope.1.contains(\"API call timed out\"),\n        \"reason should carry the timeout context: {}\",\n        interrupted_envelope.1\n    );\n\n    tokio::time::timeout(Duration::from_secs(5), task_handle)\n        .await\n        .expect(\"sub-agent task must not park waiting for checkpoint input\")\n        .expect(\"sub-agent task should finish\");\n    assert_eq!(\n        calls.load(Ordering::SeqCst),\n        SUBAGENT_API_TIMEOUT_MAX_RETRIES.saturating_add(1) as usize,\n        \"needs-input interruption must not park for continuation; the API call \\\n         is retried up to the timeout-retry budget, then stops\"\n    );\n","sourceCodeStart":8987,"sourceCodeEnd":9023,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/tools/subagent/tests.rs#L8987-L9023","documentation":"Panic from `.expect(\"API timeout should publish an Interrupted mailbox lifecycle event\")`: the test's polling future completed without ever draining a MailboxMessage::Interrupted from mailbox_rx within 5 seconds. It asserts that an API timeout is surfaced to the parent as an Interrupted lifecycle event with an 'API call timed out' reason.","triggerScenarios":"The sub-agent times out on its API call but the Interrupted mailbox message is never published (or is published with a different variant/topic), or the drain loop misses it before the timeout elapses.","commonSituations":"Refactor of the mailbox event enum or publish path dropping the Interrupted emission on the timeout branch; reason string changed so the later contains(\"API call timed out\") also fails; channel closed early.","solutions":["Check that the API-timeout branch in the sub-agent turn loop publishes MailboxMessage::Interrupted","Confirm the reason string still contains \"API call timed out\"","Verify mailbox_rx is subscribed/connected before the task starts so early events aren't lost","Increase polling frequency or drain-before-timeout if events arrive after the 5s window"],"exampleFix":"// before\n.await.expect(\"API timeout should publish an Interrupted mailbox lifecycle event\");\n// after\n.await.unwrap_or_else(|| panic!(\"no Interrupted event within 5s; drained={:?}\", seen_ids));","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn find_interrupted(msgs: &[MailboxMessage]) -> Option<&MailboxMessage> {\n    msgs.iter().find(|m| matches!(m, MailboxMessage::Interrupted { .. }))\n}","tryCatchPattern":"match tokio::time::timeout(Duration::from_secs(5), poll_interrupted()).await {\n    Ok(env) => env,\n    Err(_) => panic!(\"Interrupted mailbox event never published\"),\n}","preventionTips":["Publish lifecycle events before returning from the task so ordering is deterministic","Use a bounded wait with an assertion on drained messages for diagnostics","Keep lifecycle reason strings in constants shared with tests"],"tags":["rust","tokio","mailbox","subagent","lifecycle-event"],"backgroundTag":"unexpected-response-shape","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T01:17:13.364Z"}