{"record":{"id":"56d57abd14f1fd51","repo":"spring-projects/spring-ai","slug":"retry-error-retry-count-56d57a","errorCode":null,"errorMessage":"Retry error. Retry count:","messagePattern":"Retry error\\. Retry count:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java","lineNumber":127,"sourceCode":"\t\tRetryPolicy retryPolicy = RetryPolicy.builder()\n\t\t\t.maxRetries(DEFAULT_MAX_ATTEMPTS)\n\t\t\t.includes(TransientAiException.class)\n\t\t\t.includes(ResourceAccessException.class)\n\t\t\t.delay(Duration.ofMillis(DEFAULT_INITIAL_INTERVAL))\n\t\t\t.multiplier(DEFAULT_MULTIPLIER)\n\t\t\t.maxDelay(Duration.ofMillis(DEFAULT_MAX_INTERVAL))\n\t\t\t.build();\n\n\t\tRetryTemplate retryTemplate = new RetryTemplate(retryPolicy);\n\t\tretryTemplate.setRetryListener(new RetryListener() {\n\t\t\tprivate final AtomicInteger retryCount = new AtomicInteger(0);\n\n\t\t\t@Override\n\t\t\tpublic void onRetryFailure(final RetryPolicy policy, final Retryable<?> retryable,\n\t\t\t\t\tfinal Throwable throwable) {\n\t\t\t\tint currentRetries = this.retryCount.incrementAndGet();\n\t\t\t\tif (LOGGER.isWarnEnabled()) {\n\t\t\t\t\tLOGGER.warn(\"Retry error. Retry count:\" + currentRetries, throwable);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn retryTemplate;\n\t}\n\n\t/**\n\t * Useful in testing scenarios where you don't want to wait long for retry and don't\n\t * need to show stack trace.\n\t * @return a RetryTemplate with short delays\n\t */\n\tprivate static RetryTemplate createShortRetryTemplate() {\n\t\tRetryPolicy retryPolicy = RetryPolicy.builder()\n\t\t\t.maxRetries(DEFAULT_MAX_ATTEMPTS)\n\t\t\t.includes(TransientAiException.class)\n\t\t\t.includes(ResourceAccessException.class)\n\t\t\t.delay(Duration.ofMillis(SHORT_INITIAL_INTERVAL))\n\t\t\t.build();","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java#L109-L145","documentation":"RetryUtils builds a RetryTemplate whose onRetryFailure listener logs this warning with an incrementing retry count each time an attempt fails and will be retried. It is not a terminal error; it signals a transient failure of the retried operation, and the original throwable is attached to the log record.","triggerScenarios":"Any API call executed through a RetryUtils-built RetryTemplate (e.g. RetryUtils.DEFAULT_RETRY_TEMPLATE) whose underlying invocation throws a retryable exception, such as a NonTransientAiException/timeouts or HTTP 5xx from a model provider.","commonSituations":"Provider rate limits (429) or temporary 5xx responses; network blips between app and model API; slow responses hitting read timeouts that the retry policy tolerates.","solutions":["Inspect the attached throwable in the log to fix the root cause (credentials, quota, endpoint).","Tune the RetryTemplate's maxAttempts/backoff if retries are burning quota without success.","Ensure client-side timeouts exceed provider latency expectations to avoid spurious retries."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    result = retryTemplate.execute(ctx -> callApi());\n} catch (NonTransientAiException e) {\n    // retries exhausted; inspect warn logs 'Retry error. Retry count:N' for the root cause\n    log.error(\"Model call failed after retries\", e);\n}","preventionTips":["Right-size timeouts so attempts don't fail spuriously.","Handle 429s with backoff and quota monitoring.","Monitor the warn logs to detect provider incidents early."],"tags":["retry","retry-template","transient-failure","resilience"],"backgroundTag":"api-request-failed","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}