From e75564a92ad515da614e082e5597e2f14bdd657d Mon Sep 17 00:00:00 2001 From: Richard Feldman Date: Wed, 2 Sep 2026 14:47:22 +0000 Subject: [PATCH] language_model_core: Classify Anthropic prompt-too-long 400s as context overflow (#63596) Anthropic reports a context-window overflow with HTTP 400 and a message of the form `prompt is too long: N tokens > M maximum`. The `BAD_REQUEST` arm of `ProviderErrorCategory::from_http_status` only recognized OpenAI's phrasings (`context_length_exceeded`, "exceeds the context window"), and `parse_prompt_too_long` only ran for HTTP 413, so these rejections were classified as `InvalidRequest` instead of `PromptTooLarge`. This affects every wire path that classifies by upstream HTTP status, including Zed cloud's `upstream_http_400` code, and it silently disables any downstream handling keyed on the `PromptTooLarge` category. This change sniffs the Anthropic phrasing on 400 responses too, carrying the provider-reported token count. Closes AI-462 Release Notes: - Fixed Anthropic "prompt is too long" errors reported with HTTP 400 not being recognized as context-window overflows. --- .../src/language_model_core.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/language_model_core/src/language_model_core.rs b/crates/language_model_core/src/language_model_core.rs index 470844f8f0..adf14a90b3 100644 --- a/crates/language_model_core/src/language_model_core.rs +++ b/crates/language_model_core/src/language_model_core.rs @@ -148,9 +148,18 @@ impl ProviderErrorCategory { StatusCode::BAD_REQUEST if is_invalid_encrypted_content_message(message) => { Self::InvalidEncryptedContent } - StatusCode::BAD_REQUEST if is_context_window_exceeded_message(message) => { - Self::PromptTooLarge { tokens: None } - } + // Anthropic reports a context-window overflow as HTTP 400 with a + // "prompt is too long" message rather than HTTP 413, so a + // bad request must be sniffed for both providers' phrasings. + StatusCode::BAD_REQUEST => match parse_prompt_too_long(message) { + Some(tokens) => Self::PromptTooLarge { + tokens: Some(tokens), + }, + None if is_context_window_exceeded_message(message) => { + Self::PromptTooLarge { tokens: None } + } + None => Self::InvalidRequest, + }, StatusCode::UNAUTHORIZED => Self::Authentication, StatusCode::FORBIDDEN => Self::Permission, StatusCode::NOT_FOUND => Self::EndpointNotFound, @@ -158,7 +167,6 @@ impl ProviderErrorCategory { StatusCode::PAYLOAD_TOO_LARGE => Self::PromptTooLarge { tokens: parse_prompt_too_long(message), }, - StatusCode::BAD_REQUEST => Self::InvalidRequest, StatusCode::CONFLICT => Self::Conflict, StatusCode::REQUEST_TIMEOUT | StatusCode::GATEWAY_TIMEOUT => Self::Timeout, StatusCode::TOO_MANY_REQUESTS => Self::RateLimit,