tinyhumansai/openhuman · error · anyhow::Error
[claude_agent_sdk] claude subprocess exited with non-zero st
Error message
[claude_agent_sdk] claude subprocess exited with non-zero status {} and no output; stderr={} What it means
The claude CLI child process exited with a non-zero status AND the provider collected no usable output — neither a final `Result` text nor any streamed `Text` parts. The captured stderr is included in the message. This is the last-resort diagnosis when the CLI died before saying anything useful on stdout.
Source
Thrown at src/openhuman/inference/provider/claude_agent_sdk/subprocess.rs:236
let status = timeout(Duration::from_secs(30), child.wait())
.await
.map_err(|_| {
anyhow::anyhow!("[claude_agent_sdk] subprocess timed out while waiting for exit")
})??;
let stderr_output = stderr_task.await.unwrap_or_default();
tracing::debug!("[claude_agent_sdk] subprocess exited status={}", status);
if let Some(err) = error_message {
anyhow::bail!("[claude_agent_sdk] error from claude CLI: {err}");
}
// Use the final result message if present; otherwise join streaming text parts.
let output = result_text
.filter(|s| !s.is_empty())
.unwrap_or_else(|| text_parts.join(""));
if !status.success() && output.is_empty() {
anyhow::bail!(
"[claude_agent_sdk] claude subprocess exited with non-zero status {} and no output; stderr={}",
status,
stderr_output
);
}
tracing::debug!(
"[claude_agent_sdk] response collected output_len={}",
output.len()
);
Ok(output)
}
}
#[async_trait]
impl ChatModel<()> for ClaudeAgentSdkProvider {
fn profile(&self) -> Option<&ModelProfile> {View on GitHub (pinned to 7491200858)
Solutions
- Read the `stderr=` portion of the message — it usually contains the crash reason (missing module, bad flag, auth failure).
- Run the same CLI manually (`claude --version`, then a trivial prompt) to reproduce the crash outside the app.
- Reinstall/upgrade the claude CLI (`npm i -g @anthropic-ai/claude-code` or the native installer) to repair a broken auto-updated install.
- If stderr shows OOM/signal kill, free memory or reduce parallel agent turns.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: does the CLI start and emit a version at all?
fn claude_cli_bootable() -> bool {
std::process::Command::new("claude")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
} Try / catch
match provider.chat(req).await {
Err(e) if e.to_string().contains("non-zero status") => {
log::error!("claude CLI crashed: {e}"); // stderr is embedded — log it for triage
Err(e)
}
other => other,
} Prevention
- Pin/verify the claude CLI version at deploy time so auto-updates can't break the binary mid-service.
- Run a `--version` smoke check in startup health checks.
- Reserve headroom for the CLI process on memory-constrained hosts.
When it happens
Trigger: The `claude` binary crashes at startup (bad flag, missing runtime like an incompatible Node version), fails auth before emitting NDJSON, or is killed by the OS (OOM, signal). Only fires when `!status.success() && output.is_empty()` — a non-zero exit WITH output is treated as success.
Common situations: CLI binary/arch mismatch after an OS update, claude CLI auto-update mid-run leaving a broken install, node runtime unavailable to the CLI wrapper, OOM killer terminating the child on memory-constrained machines, or an invalid CLI flag introduced by a version skew between the core's arg builder and the installed CLI.
Related errors
- [claude_agent_sdk] subprocess timed out while reading output
- [claude-code][driver] exit {:?} stderr={}
- Failed to parse service CLI output as JSON: ${err instanceof
- [claude_agent_sdk] error from claude CLI: {err}
- command failed with status {status}
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/9a786f63dd8dfbb6.
Report an issue: GitHub.