{"record":{"id":"0319b8d346f60407","repo":"spring-projects/spring-ai","slug":"http-s-s","errorCode":null,"errorMessage":"HTTP %s - %s","messagePattern":"HTTP (.+?) - (.+?)","errorType":"exception","errorClass":"TransientAiException","httpStatus":null,"severity":"warning","filePath":"auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java","lineNumber":120,"sourceCode":"\t\t\t\thandleError(response);\n\t\t\t}\n\n\t\t\t@SuppressWarnings(\"removal\")\n\t\t\tpublic void handleError(ClientHttpResponse response) throws IOException {\n\t\t\t\tif (!response.getStatusCode().isError()) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tString error = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8);\n\t\t\t\tif (error == null || error.isEmpty()) {\n\t\t\t\t\terror = \"No response body available\";\n\t\t\t\t}\n\n\t\t\t\tString message = String.format(\"HTTP %s - %s\", response.getStatusCode().value(), error);\n\n\t\t\t\t// Explicitly configured transient codes\n\t\t\t\tif (properties.getOnHttpCodes().contains(response.getStatusCode().value())) {\n\t\t\t\t\tthrow new TransientAiException(message);\n\t\t\t\t}\n\n\t\t\t\t// Handle client errors (4xx)\n\t\t\t\tif (!properties.isOnClientErrors() && response.getStatusCode().is4xxClientError()) {\n\t\t\t\t\tthrow new NonTransientAiException(message);\n\t\t\t\t}\n\n\t\t\t\t// Explicitly configured non-transient codes\n\t\t\t\tif (!CollectionUtils.isEmpty(properties.getExcludeOnHttpCodes())\n\t\t\t\t\t\t&& properties.getExcludeOnHttpCodes().contains(response.getStatusCode().value())) {\n\t\t\t\t\tthrow new NonTransientAiException(message);\n\t\t\t\t}\n\n\t\t\t\t// Default to transient exception\n\t\t\t\tthrow new TransientAiException(message);\n\t\t\t}\n\t\t};\n\t}","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/auto-configurations/common/spring-ai-autoconfigure-retry/src/main/java/org/springframework/ai/retry/autoconfigure/SpringAiRetryAutoConfiguration.java#L102-L138","documentation":"SpringAiRetryAutoConfiguration registers a ResponseErrorHandler that formats 'HTTP <status> - <detail>' for failing model API responses. When the returned status code is in spring.ai.retry.on-http-codes, it throws a TransientAiException so the retry template retries the request. This is the explicitly-configured transient error path.","triggerScenarios":"A model HTTP call returns a status code listed in spring.ai.retry.on-http-codes (defaults include 429, 500, 502, 503, 529) — handleError formats the message and throws TransientAiException.","commonSituations":"Rate limiting (429) from OpenAI/Anthropic, transient 5xx provider outages, proxy/gateway 502-503 errors during high traffic.","solutions":["Let the retry template handle it — tune spring.ai.retry.backoff properties (initial/interval/multiplier/max-attempts) for your provider's rate limits.","Reduce request rate or batch size if 429s are frequent.","Remove rarely-retryable codes from spring.ai.retry.on-http-codes if you prefer to fail fast on them.","Check the provider status page / API quota when persistent."],"exampleFix":"# before: default retries exhausting on 429\n# after\nspring.ai.retry.backoff.initial-interval=2000\nspring.ai.retry.backoff.multiplier=3\nspring.ai.retry.max-attempts=10","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    response = chatClient.prompt().call();\n} catch (TransientAiException e) {\n    // already retried by RetryTemplate; back off further or degrade gracefully\n    log.warn(\"Model API still failing after retries: {}\", e.getMessage());\n}","preventionTips":["Configure spring.ai.retry.backoff.* to match provider rate limits","Monitor 429 rates and add client-side throttling","Subscribe to provider status pages","Set sensible max-attempts so callers fail fast enough"],"tags":["http","retry","transient","rate-limit"],"backgroundTag":"http-error-response","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}