tinyhumansai/openhuman · error · anyhow::Error

[claude-code][driver] {}

Error message

[claude-code][driver] {}

What it means

The claude-code turn completed with exit status 0, but while parsing the CLI's stream-json events, the response mapper recorded a terminal error (e.g. an `error` event or a result message flagged as error). The mapped error string is appended to the message. Process-level checks passed; this is a protocol/semantic error carried inside a successful run.

Source

Thrown at src/openhuman/inference/provider/claude_code/driver.rs:493

            let _ = child.kill().await;
            anyhow::bail!(
                "[claude-code][driver] turn timed out after {:?}",
                TURN_TIMEOUT
            );
        }
    };

    let stderr_text = stderr_task.await.unwrap_or_default();

    if !status.success() {
        anyhow::bail!(
            "[claude-code][driver] exit {:?} stderr={}",
            status.code(),
            stderr_text.trim()
        );
    }
    if let Some(err) = mapper.error.clone() {
        anyhow::bail!("[claude-code][driver] {}", err);
    }

    Ok(mapper.into_response())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn write_mcp_http_config_emits_http_url_with_bearer_header() {
        let dir = tempfile::tempdir().expect("tempdir");
        let addr: std::net::SocketAddr = "127.0.0.1:54321".parse().unwrap();
        let path = write_mcp_http_config(dir.path(), addr, "tok-abc123").expect("write config");
        let raw = std::fs::read_to_string(&path).expect("read config");
        let v: serde_json::Value = serde_json::from_str(&raw).expect("valid json");
        let server = &v["mcpServers"]["openhuman"];
        assert_eq!(

View on GitHub (pinned to 7491200858)

Solutions

  1. Read the `{}` payload — it is the CLI's error verbatim and names the real cause.
  2. Rate-limit/overload: retry with backoff.
  3. Context-length errors: start a fresh session (drop cc_session_id continuation) or trim history.
  4. Permission-denied tool errors: run with full-access posture or allow the specific tool in the project's claude settings.
Defensive patterns

Strategy: try-catch

Try / catch

match driver.run(ctx).await {
    Err(e) => {
        let s = e.to_string();
        if s.starts_with("[claude-code][driver]") && !s.contains("exit") && !s.contains("timed out") {
            // in-stream CLI error: branch on content (rate limit vs context vs permission)
            classify_and_handle(&s);
        }
        Err(e)
    }
    ok => ok,
}

Prevention

When it happens

Trigger: The CLI emits a stream-json error event mid-turn (API overload, permission denial for a tool, context-length exceeded) but still exits 0. `mapper.error` is `Some`, so the driver converts it into a failure for the caller.

Common situations: Anthropic-side errors (429/529) surfaced as in-stream events; tool-use denials under the `acceptEdits`/limited permission posture; conversation exceeding the model context window mid-turn.

Related errors


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