{"record":{"id":"dfcdb837a20e84ec","repo":"tinyhumansai/openhuman","slug":"claude-code-driver-turn-timed-out-after","errorCode":null,"errorMessage":"[claude-code][driver] turn timed out after {:?}","messagePattern":"\\[claude-code\\]\\[driver\\] turn timed out after (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/inference/provider/claude_code/driver.rs","lineNumber":476,"sourceCode":"\n        let status = child\n            .wait()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"wait child: {e}\"))?;\n        Ok::<_, anyhow::Error>(status)\n    })\n    .await;\n\n    let status = match timed {\n        Ok(inner) => inner?,\n        Err(_elapsed) => {\n            log::error!(\n                \"[claude-code][driver] turn timeout ({TURN_TIMEOUT:?}) exceeded; killing child\"\n            );\n            // kill_on_drop handles cleanup, but explicit kill gives us\n            // a chance to collect stderr.\n            let _ = child.kill().await;\n            anyhow::bail!(\n                \"[claude-code][driver] turn timed out after {:?}\",\n                TURN_TIMEOUT\n            );\n        }\n    };\n\n    let stderr_text = stderr_task.await.unwrap_or_default();\n\n    if !status.success() {\n        anyhow::bail!(\n            \"[claude-code][driver] exit {:?} stderr={}\",\n            status.code(),\n            stderr_text.trim()\n        );\n    }\n    if let Some(err) = mapper.error.clone() {\n        anyhow::bail!(\"[claude-code][driver] {}\", err);\n    }","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/inference/provider/claude_code/driver.rs#L458-L494","documentation":"The entire claude-code turn — spawn, stream, and exit — is wrapped in a hard 300-second (`TURN_TIMEOUT`, driver.rs:19) tokio timeout. When the child does not finish within 5 minutes, the driver logs a timeout, explicitly kills the child (kill_on_drop is the backstop; the explicit kill lets stderr be collected), and bails with this message.","triggerScenarios":"Any claude-code turn whose CLI process runs longer than 300s: a large refactor with many tool iterations, a hung MCP tool call, a CLI permission prompt blocking in non-interactive mode, or a stalled network uplink. Fires from the `Err(_elapsed)` arm of `tokio::time::timeout(TURN_TIMEOUT, ...)` at driver.rs:434.","commonSituations":"Big agentic coding tasks that legitimately exceed 5 minutes; an MCP server tool that never returns; the CLI waiting for interactive trust approval on a new project directory; saturated corporate proxy blocking streaming responses.","solutions":["Retry once — transient stalls (proxy hiccup, API slowdown) commonly clear.","If turns legitimately exceed 5 minutes in your workload, raise `TURN_TIMEOUT` in driver.rs:19 (it is a single const) and rebuild.","Check `claude mcp list` for MCP servers whose tools hang; fix or remove them.","Ensure the project dir is pre-trusted (run `claude` once interactively in it) so the CLI never blocks on a trust prompt."],"exampleFix":"// before\nconst TURN_TIMEOUT: Duration = Duration::from_secs(300);\n\n// after — allow long agentic turns\nconst TURN_TIMEOUT: Duration = Duration::from_secs(900);","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let attempt = tokio::time::timeout(Duration::from_secs(330), provider.chat(req)).await;\nmatch attempt {\n    Ok(Err(e)) if e.to_string().contains(\"turn timed out\") => {\n        // one retry; a second consecutive timeout indicates a hung MCP tool or stall\n        provider.chat(req).await\n    }\n    other => other.unwrap_or_else(|_| Err(anyhow::anyhow!(\"outer watchdog fired\"))),\n}","preventionTips":["Pre-trust project directories (one interactive `claude` run) so the CLI never blocks on prompts.","Keep MCP tool calls time-bounded so they can't consume the whole 300s turn budget.","Match TURN_TIMEOUT to your real workload; long refactors need a larger const."],"tags":["claude-code","timeout","turn-deadline","inference"],"backgroundTag":"request-timeout","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}