{"record":{"id":"cecbe53d2dd8134b","repo":"Hmbown/CodeWhale","slug":"anthropic-stream-error-error-type-message","errorCode":null,"errorMessage":"Anthropic stream error ({error_type}): {message}","messagePattern":"Anthropic stream error \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/anthropic.rs","lineNumber":358,"sourceCode":"                    let line = match super::take_sse_line(&mut buffer) {\n                        Ok(Some(line)) => line,\n                        Ok(None) => break,\n                        Err(err) => {\n                            yield Err(anyhow::anyhow!(\"{err}\"));\n                            return;\n                        }\n                    };\n\n                    // `event:` lines are redundant (the data payload carries\n                    // `type`) and comment/heartbeat lines are ignorable.\n                    let Some(data) = super::extract_sse_data_value(&line) else {\n                        continue;\n                    };\n\n                    match convert_anthropic_sse_data(data) {\n                        Some(Ok(StreamEvent::Error { error })) => {\n                            let (error_type, message) = anthropic_error_fields(&error);\n                            yield Err(anyhow::anyhow!(\n                                \"Anthropic stream error ({error_type}): {message}\"\n                            ));\n                            return;\n                        }\n                        Some(Ok(event)) => {\n                            let is_stop = matches!(event, StreamEvent::MessageStop);\n                            yield Ok(event);\n                            if is_stop {\n                                return;\n                            }\n                        }\n                        Some(Err(e)) => {\n                            logging::warn(format!(\"Failed to parse Anthropic SSE event: {e}\"));\n                        }\n                        None => {}\n                    }\n                }\n            }","sourceCodeStart":340,"sourceCodeEnd":376,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client/anthropic.rs#L340-L376","documentation":"The Anthropic SSE stream delivered an `error` event after the HTTP 200 response had already begun. The client converts it via `convert_anthropic_sse_data`, extracts `error.type` and `error.message` with `anthropic_error_fields` (defaulting to \"unknown\" and the raw JSON), yields this error, and terminates the stream with an early `return`. The connection itself was healthy; the provider reported the failure mid-generation.","triggerScenarios":"Anthropic sends `data: {\"type\":\"error\",...}` mid-stream: `overloaded_error` (529 capacity), `rate_limit_error` hit while tokens stream, `invalid_request_error` detected only after headers were sent, or a content/safety stop during generation.","commonSituations":"Sustained request volume tripping rate limits mid-response; Anthropic capacity incidents; prompts or tool schemas accepted at request time but rejected during generation; long streaming turns during provider degradation.","solutions":["Read the error_type in parentheses: retry with exponential backoff for `overloaded_error`, `rate_limit_error`, and generic `api_error`","For `invalid_request_error`, fix the request per the embedded message (tool schema, max_tokens, model name) — retrying will not help","Check status.anthropic.com before retrying when the type is `overloaded_error`","If the stop is content-policy related, adjust the prompt or tool descriptions instead of retrying"],"exampleFix":"// before\nwhile let Some(ev) = stream.next().await {\n    if let Ok(event) = ev { handle(event); }\n}\n\n// after\nwhile let Some(item) = stream.next().await {\n    match item {\n        Ok(event) => handle(event),\n        Err(e) if is_retryable_anthropic_stream_error(&e.to_string()) => {\n            backoff_and_reopen_stream().await;\n        }\n        Err(e) => return Err(e),\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_retryable_anthropic_stream_error(msg: &str) -> bool {\n    msg.starts_with(\"Anthropic stream error\")\n        && (msg.contains(\"overloaded_error\")\n            || msg.contains(\"rate_limit_error\")\n            || msg.contains(\"api_error\"))\n}","tryCatchPattern":"match stream.next().await {\n    Some(Err(e)) if is_retryable_anthropic_stream_error(&e.to_string()) => {\n        backoff().await;\n        stream = client.reopen_stream(request).await?;\n    }\n    Some(Err(e)) => return Err(e), // invalid_request_error and similar are permanent\n    Some(Ok(event)) => handle(event),\n    None => break,\n}","preventionTips":["Keep request rate below Anthropic rate limits, especially for long streaming turns","Treat `invalid_request_error` as a request bug — fix the payload, never retry it","Monitor for `overloaded_error` bursts before they become hard failures"],"tags":["anthropic","sse","streaming","api"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}