Hmbown/CodeWhale · error · anyhow::Error

Anthropic stream error

Error message

Anthropic stream error ({error_type}): {message}

What it means

The Anthropic SSE stream delivered an explicit error event (type "error" carrying an error object). The handler extracts the error.type and error.message fields and surfaces them as a Rust error, then stops the stream — this is the server reporting a failure in-band.

Solutions

  1. Read error_type in the message: overloaded_error/rate_limit_error → back off and retry with exponential delay
  2. invalid_request_error → fix the request: model name, max_tokens, prompt size, parameter names
  3. authentication_error → refresh/verify the API key
  4. Check the Anthropic status page if overloaded_error persists across retries
  5. Respect the Retry-After semantics / documented rate limits to avoid repeat hits
Defensive patterns

Strategy: try-catch

Try / catch

match result {
    Err(e) => {
        let msg = e.to_string();
        if msg.contains("overloaded_error") || msg.contains("rate_limit_error") {
            tokio::time::sleep(backoff).await;
            retry_request()
        } else if msg.contains("invalid_request_error") {
            Err(anyhow!("bad request: {msg}"))
        } else { Err(e) }
    }
    Ok(v) => Ok(v),
}

Prevention

When it happens

Trigger: Anthropic sends an SSE event {"type":"error","error":{"type":...,"message":...}}: overloaded_error (server overloaded), rate_limit_error, invalid_request_error (bad model/params), api_error, authentication_error mid-stream after the connection was already established.

Common situations: Hitting rate limits during heavy usage; Anthropic capacity issues returning overloaded_error; an invalid model name or oversized request accepted at connection time but rejected during streaming; an API key losing validity mid-session.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/cecbe53d2dd8134b. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client/anthropic.rs:366

                    let line = match next_sse_line(&mut buffer, ended) {
                        Ok(Some(line)) => line,
                        Ok(None) => break,
                        Err(err) => {
                            yield Err(anyhow::anyhow!("{err}"));
                            return;
                        }
                    };

                    // `event:` lines are redundant (the data payload carries
                    // `type`) and comment/heartbeat lines are ignorable.
                    let Some(data) = extract_sse_data_value(&line) else {
                        continue;
                    };

                    match convert_anthropic_sse_data(data) {
                        Some(Ok(StreamEvent::Error { error })) => {
                            let (error_type, message) = anthropic_error_fields(&error);
                            yield Err(anyhow::anyhow!(
                                "Anthropic stream error ({error_type}): {message}"
                            ));
                            return;
                        }
                        Some(Ok(event)) => {
                            let is_stop = matches!(event, StreamEvent::MessageStop);
                            yield Ok(event);
                            if is_stop {
                                return;
                            }
                        }
                        Some(Err(e)) => {
                            logging::warn(format!("Failed to parse Anthropic SSE event: {e}"));
                        }
                        None => {}
                    }
                }

View on GitHub (pinned to 73e0f67d83)