{"record":{"id":"0d793aa81fbdd241","repo":"Hmbown/CodeWhale","slug":"first-timed-out-api-attempt-should-reach-the-test-server","errorCode":null,"errorMessage":"first timed-out API attempt should reach the test server","messagePattern":"first timed-out API attempt should reach the test server","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/tests.rs","lineNumber":8988,"sourceCode":"        max_steps: 3,\n        token_budget: None,\n        wall_time: DEFAULT_CHILD_WALL_TIME,\n        input_rx: task_input_rx,\n        launch_gate: None,\n        _foreground_child_registration: None,\n    };\n    let task_handle = tokio::spawn(run_subagent_task(task));\n\n    tokio::time::timeout(Duration::from_secs(5), async {\n        loop {\n            if calls.load(Ordering::SeqCst) >= 1 {\n                break;\n            }\n            tokio::time::sleep(Duration::from_millis(10)).await;\n        }\n    })\n    .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);","sourceCodeStart":8970,"sourceCodeEnd":9006,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/crates/tui/src/tools/subagent/tests.rs#L8970-L9006","documentation":"Panic from `.expect(\"first timed-out API attempt should reach the test server\")` on a `tokio::time::timeout` wrapping a polling loop. The test awaited the axum test server recording at least one API call within the window after a deliberately timed-out first attempt; if the loop ends without seeing the call, the retry/timeout machinery failed to re-issue the request.","triggerScenarios":"Running api_timeout_preserves_checkpoint_and_returns_needs_input_without_parking when the sub-agent's retry path does not re-send the API request after the first attempt times out, or the mock server's request counter never increments within the awaited window.","commonSituations":"A regression in SUBAGENT_API_TIMEOUT retry logic (retries skipped or retried against the wrong client), mock server bound to a different port, or the polling loop checking the wrong counter.","solutions":["Verify the retry path in SubAgentManager actually re-issues the API call after the client timeout","Confirm the mock axum server increments the `calls` counter on each request","Check that the timeout windows (client timeout vs test timeout) leave room for the retry to be observed","Inspect test logs for the first attempt's timeout firing before the loop starts"],"exampleFix":"// before\n.await.expect(\"first timed-out API attempt should reach the test server\");\n// after\n.await.unwrap_or_else(|| panic!(\n    \"no API attempt reached the test server after timeout; calls={}\\\",\n    calls.load(Ordering::SeqCst)\"));","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"tokio::time::timeout(Duration::from_secs(5), poll_for_call())\n    .await\n    .unwrap_or_else(|_| panic!(\"retry never reached test server; calls={}\", calls.load(Ordering::SeqCst)));","preventionTips":["Keep client timeouts comfortably smaller than test await windows","Log each mock-server hit so retries are observable in failures","Assert the retry count alongside reachability to distinguish no-retry from slow-retry"],"tags":["rust","tokio","timeout","subagent","test"],"backgroundTag":"request-timeout","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"}