Hmbown/CodeWhale · error · anyhow::Error
Anthropic API error (HTTP )
Error message
Anthropic API error (HTTP {status} {error_type}): {message} What it means
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).
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.
Defensive patterns
Strategy: retry
Validate before calling
fn anthropic_error_is_retryable(status: u16, error_type: &str) -> bool {
status == 429 || status == 529 || status >= 500 || error_type == "overloaded_error"
} Try / catch
match client.send_anthropic_request(req).await {
Err(e) if e.to_string().starts_with("Anthropic API error") => {
let (status, etype) = parse_anthropic_error(&e.to_string());
if anthropic_error_is_retryable(status, &etype) {
retry_with_exponential_backoff().await
} else {
surface_to_user(&e) // 401 key, 404 model, 400 payload
}
}
other => other,
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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).
Related errors
- Anthropic stream error
- Cloud agent sandbox listing failed
- Cloudflare SQL request failed
- CNB pull request create failed
- Codewhale account request failed
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1f24b3b238f29655.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/client/anthropic.rs:242
.send()
.await
.context("Anthropic Messages API request failed")?;
self.check_anthropic_response(response).await
}
/// Shared status/error-envelope handling for streaming and
/// non-streaming Messages responses.
async fn check_anthropic_response(
&self,
response: reqwest::Response,
) -> Result<reqwest::Response> {
let status = response.status();
if !status.is_success() {
let raw = bounded_error_text(response, ERROR_BODY_MAX_BYTES).await;
let (error_type, message) = parse_anthropic_error_envelope(&raw);
self.mark_request_failure(&format!("anthropic status={status}"))
.await;
anyhow::bail!("Anthropic API error (HTTP {status} {error_type}): {message}");
}
self.mark_request_success().await;
Ok(response)
}
/// Open the streaming Messages request through the shared stream-entry
/// transport policy: bounded header wait, dual-client selection, and at
/// most one HTTP/1.1 fallback retry on a classified H2 header stall.
/// Wire-specific request construction (headers, endpoint, body) stays
/// here at the adapter edge.
async fn open_anthropic_stream_response(
&self,
url: &str,
body: &Value,
) -> Result<reqwest::Response> {
let url = self.messages_transport_url(url);
let open_req = super::stream_entry::StreamOpenRequest::new(
super::stream_entry::stream_open_timeout(),View on GitHub (pinned to 73e0f67d83)