spring-projects/spring-ai · warning
Retry error. Retry count:
Error message
Retry error. Retry count:
What it means
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.
Source
Thrown at spring-ai-retry/src/main/java/org/springframework/ai/retry/RetryUtils.java:127
RetryPolicy retryPolicy = RetryPolicy.builder()
.maxRetries(DEFAULT_MAX_ATTEMPTS)
.includes(TransientAiException.class)
.includes(ResourceAccessException.class)
.delay(Duration.ofMillis(DEFAULT_INITIAL_INTERVAL))
.multiplier(DEFAULT_MULTIPLIER)
.maxDelay(Duration.ofMillis(DEFAULT_MAX_INTERVAL))
.build();
RetryTemplate retryTemplate = new RetryTemplate(retryPolicy);
retryTemplate.setRetryListener(new RetryListener() {
private final AtomicInteger retryCount = new AtomicInteger(0);
@Override
public void onRetryFailure(final RetryPolicy policy, final Retryable<?> retryable,
final Throwable throwable) {
int currentRetries = this.retryCount.incrementAndGet();
if (LOGGER.isWarnEnabled()) {
LOGGER.warn("Retry error. Retry count:" + currentRetries, throwable);
}
}
});
return retryTemplate;
}
/**
* Useful in testing scenarios where you don't want to wait long for retry and don't
* need to show stack trace.
* @return a RetryTemplate with short delays
*/
private static RetryTemplate createShortRetryTemplate() {
RetryPolicy retryPolicy = RetryPolicy.builder()
.maxRetries(DEFAULT_MAX_ATTEMPTS)
.includes(TransientAiException.class)
.includes(ResourceAccessException.class)
.delay(Duration.ofMillis(SHORT_INITIAL_INTERVAL))
.build();View on GitHub (pinned to 98a7beda4f)
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.
Defensive patterns
Strategy: retry
Try / catch
try {
result = retryTemplate.execute(ctx -> callApi());
} catch (NonTransientAiException e) {
// retries exhausted; inspect warn logs 'Retry error. Retry count:N' for the root cause
log.error("Model call failed after retries", e);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/56d57abd14f1fd51.
Report an issue: GitHub.