tinyhumansai/openhuman · error · anyhow::Error

[claude_agent_sdk] error from claude CLI: {err}

Error message

[claude_agent_sdk] error from claude CLI: {err}

What it means

While draining the claude CLI's NDJSON stdout, the provider received an explicit error message from the CLI itself — either a `Result` message with `is_error: true` or a top-level `Error` event (subprocess.rs:172-193). The subprocess completed; the failure is semantic (the CLI's agent turn failed), not a process or transport failure. The CLI's own error text is appended to the message.

Source

Thrown at src/openhuman/inference/provider/claude_agent_sdk/subprocess.rs:227

        match read_result {
            Ok(inner) => inner?,
            Err(_) => {
                let _ = child.kill().await;
                anyhow::bail!("[claude_agent_sdk] subprocess timed out while reading output");
            }
        }

        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()

View on GitHub (pinned to 7491200858)

Solutions

  1. Read the `{err}` text — it is the CLI's verbatim reason (e.g. 'credit balance too low', 'rate_limit_error') and determines the fix.
  2. For rate-limit/overload errors: retry with backoff; the failure is server-side and transient.
  3. For auth errors: run `claude login` (or set the API key env the CLI uses) in the same user context as the core.
  4. For request-shape errors (context too long): shrink the conversation or clear the session so the CLI starts a fresh context.
Defensive patterns

Strategy: try-catch

Try / catch

if let Err(e) = provider.chat(req).await {
    let msg = e.to_string();
    if msg.contains("error from claude CLI") {
        // parse the trailing CLI text for rate_limit / credit / auth causes and branch
        if msg.contains("rate_limit") || msg.contains("overloaded") {
            backoff_retry(req).await;
        } else {
            surface_to_user(msg);
        }
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: The claude CLI returns an NDJSON result with `is_error` set (e.g. overloaded API, invalid request, credit/limit problem, disallowed tool use) or emits an `Error { message }` event. Any `chat` call routed to the claude_agent_sdk provider that ends in a CLI-side error.

Common situations: Anthropic API rate limits or 529 overloaded responses surfaced through the CLI, expired or invalid claude CLI login credentials, a prompt/request the CLI refuses (context overflow, forbidden tool), or quota exhaustion on the account.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17). Data as JSON: /api/errors/a70913c2b290d1a3. Report an issue: GitHub.