{"record":{"id":"6858a84dfd712c08","repo":"tinyhumansai/openhuman","slug":"claude-code-driver-exit-stderr","errorCode":null,"errorMessage":"[claude-code][driver] exit {:?} stderr={}","messagePattern":"\\[claude-code\\]\\[driver\\] exit (.+?) stderr=(.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/openhuman/inference/provider/claude_code/driver.rs","lineNumber":486,"sourceCode":"        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    }\n\n    Ok(mapper.into_response())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn write_mcp_http_config_emits_http_url_with_bearer_header() {","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/inference/provider/claude_code/driver.rs#L468-L504","documentation":"The claude-code CLI child exited with a non-zero exit status. Unlike the agent-sdk path, output may have been streamed, but the process itself failed; the exit code and trimmed stderr are included in the message. This indicates a process-level failure (crash, CLI-side abort) rather than a well-formed in-stream error.","triggerScenarios":"The `claude` CLI exits non-zero during a claude-code turn: startup failure (bad flag/`--print-mode` incompatibility with the installed CLI version), runtime crash, auth failure at boot, or external kill. Fires whenever `!status.success()` after the turn completes within TURN_TIMEOUT.","commonSituations":"Version skew — the installed CLI removed/renamed a flag the driver passes; broken CLI install after auto-update; invalid API credentials causing the CLI to exit at startup; OS-level kills (OOM).","solutions":["Match on the `exit {:?}` code and `stderr=` text: exit 2 with usage text usually means an unsupported flag → update the CLI or the core.","Update the claude CLI to the latest version so the driver's flags and the CLI agree.","Run the failing command manually with the same args (visible in the `[claude-code][driver] spawn` debug log) to reproduce.","For OOM/kill exits, reduce concurrent turns or increase available memory."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = driver.run(ctx).await {\n    let s = e.to_string();\n    if s.contains(\"exit\") && s.contains(\"stderr=\") {\n        // extract stderr for triage; exit 2 + usage text ⇒ flag/version skew ⇒ update CLI\n        report_cli_update_needed(s);\n    }\n    return Err(e);\n}","preventionTips":["Version-pin the claude CLI in CI/dev environments and test against it.","Smoke-test one trivial claude-code turn after every CLI update.","Capture the `[claude-code][driver] spawn` debug line to reproduce failures manually."],"tags":["claude-code","subprocess","exit-code","stderr"],"backgroundTag":"cli-nonzero-exit","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}