{"record":{"id":"1f24b3b238f29655","repo":"Hmbown/CodeWhale","slug":"anthropic-api-error-http-status-error-type","errorCode":null,"errorMessage":"Anthropic API error (HTTP {status} {error_type}): {message}","messagePattern":"Anthropic API error \\(HTTP (.+?) (.+?)\\): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/anthropic.rs","lineNumber":242,"sourceCode":"            .send()\n            .await\n            .context(\"Anthropic Messages API request failed\")?;\n        self.check_anthropic_response(response).await\n    }\n\n    /// Shared status/error-envelope handling for streaming and\n    /// non-streaming Messages responses.\n    async fn check_anthropic_response(\n        &self,\n        response: reqwest::Response,\n    ) -> Result<reqwest::Response> {\n        let status = response.status();\n        if !status.is_success() {\n            let raw = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;\n            let (error_type, message) = parse_anthropic_error_envelope(&raw);\n            self.mark_request_failure(&format!(\"anthropic status={status}\"))\n                .await;\n            anyhow::bail!(\"Anthropic API error (HTTP {status} {error_type}): {message}\");\n        }\n        self.mark_request_success().await;\n        Ok(response)\n    }\n\n    /// Open the streaming Messages request through the shared stream-entry\n    /// transport policy: bounded header wait, dual-client selection, and at\n    /// most one HTTP/1.1 fallback retry on a classified H2 header stall.\n    /// Wire-specific request construction (headers, endpoint, body) stays\n    /// here at the adapter edge.\n    async fn open_anthropic_stream_response(\n        &self,\n        url: &str,\n        body: &Value,\n    ) -> Result<reqwest::Response> {\n        let url = self.messages_transport_url(url);\n        let open_req = super::stream_entry::StreamOpenRequest::new(\n            super::stream_entry::stream_open_timeout(),","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/client/anthropic.rs#L224-L260","documentation":"Shared checker for Anthropic Messages requests (both one-shot and streaming): when the HTTP response is non-success, the bounded raw body is parsed by `parse_anthropic_error_envelope` into Anthropic's `error.type` and `error.message`, the request failure is recorded in the breaker, and the pair is re-raised with the HTTP status. This is the canonical surface for all upstream Anthropic errors (overloaded, invalid_request, auth, permission, rate limit).","triggerScenarios":"Any non-success status from the Anthropic Messages endpoint — 400 invalid_request_error (bad payload/tool schema), 401 authentication_error (bad API key), 403 permission_error, 404 not_found_error (bad model name), 413/429 request_too_large/rate_limit_error, 529/500 overloaded_error (Anthropic capacity).","commonSituations":"Expired or wrong `ANTHROPIC_API_KEY`; requesting a model id the key cannot access; tool-use payloads failing schema validation; hitting Anthropic's `overloaded_error` during capacity events; context length exceeded (invalid_request).","solutions":["Read `error_type` and `message` in the error: 401 → fix the API key; 404 → fix the model id; 429 → back off; 529 → retry later.","For 400 invalid_request_error, inspect the message for which field/tool schema the API rejected.","Enable retry/backoff for 429/529 statuses; the failure is also recorded via `mark_request_failure` for circuit-breaker handling.","Verify the account has access to the requested Anthropic model."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"fn anthropic_error_is_retryable(status: u16, error_type: &str) -> bool {\n    status == 429 || status == 529 || status >= 500 || error_type == \"overloaded_error\"\n}","typeGuard":null,"tryCatchPattern":"match client.send_anthropic_request(req).await {\n    Err(e) if e.to_string().starts_with(\"Anthropic API error\") => {\n        let (status, etype) = parse_anthropic_error(&e.to_string());\n        if anthropic_error_is_retryable(status, &etype) {\n            retry_with_exponential_backoff().await\n        } else {\n            surface_to_user(&e) // 401 key, 404 model, 400 payload\n        }\n    }\n    other => other,\n}","preventionTips":["Match on error_type: authentication_error → fix key; not_found_error → fix model id; overloaded_error → retry.","Add exponential backoff with jitter for 429/529/5xx.","Keep payloads within context limits to avoid invalid_request_error.","Rotate/verify ANTHROPIC_API_KEY before long sessions."],"tags":["http","anthropic","api"],"backgroundTag":"api-error-response","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}