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

  1. Inspect the attached throwable in the log to fix the root cause (credentials, quota, endpoint).
  2. Tune the RetryTemplate's maxAttempts/backoff if retries are burning quota without success.
  3. 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

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.