alibaba/spring-ai-alibaba · error · RuntimeException

Model call failed, maximum number of retries reached. ${maxA

Error message

Model call failed, maximum number of retries reached. ${maxAttempts}

What it means

Defensive terminal throw after ModelRetryInterceptor's for-loop over attempts completes without returning — all maxAttempts attempts failed with retryable errors. It throws RuntimeException("Model call failed, maximum number of retries reached. " + maxAttempts) with the last exception as cause. (In practice usually unreachable because line 132-134 throws earlier on the final attempt.)

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/modelretry/ModelRetryInterceptor.java:160

				// Wait and try again
				if (currentDelay > 0) {
					try {
						log.info("Retry after {} ms", currentDelay);
						Thread.sleep(currentDelay);
					} catch (InterruptedException ie) {
						Thread.currentThread().interrupt();
						throw new RuntimeException("Retry interrupted", ie);
					}
				}

				// Calculate the next delay time (exponential backoff)
				currentDelay = Math.min((long) (currentDelay * backoffMultiplier), maxDelay);
			}
		}

		// All retries failed.
		throw new RuntimeException("Model call failed, maximum number of retries reached. " + maxAttempts, lastException);
	}

	private Flux<ChatResponse> withStreamingRetry(ModelRequest request, ModelCallHandler handler, Flux<ChatResponse> responseFlux,
			int attempt, long currentDelay) {
		return Flux.defer(() -> {
			AtomicBoolean chunkEmitted = new AtomicBoolean(false);
			return responseFlux.doOnNext(response -> chunkEmitted.set(true)).onErrorResume(error -> {
				if (chunkEmitted.get()) {
					// Retrying after partial output would duplicate chunks downstream.
					return Flux.error(error);
				}
				return retryStreamingModelCall(request, handler, attempt, currentDelay, error);
			});
		});
	}

	private Flux<ChatResponse> retryStreamingModelCall(ModelRequest request, ModelCallHandler handler, int failedAttempt,
			long currentDelay, Throwable error) {

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Inspect the cause for the true final failure and check provider health/credentials.
  2. Increase maxAttempts, initialDelay, and maxDelay to ride out longer outages.
  3. Wrap with ModelFallbackInterceptor for cross-provider resilience.
  4. Add logging/metrics on retry exhaustion to alert before clients see this error.

Example fix

// before
ModelRetryInterceptor.builder().maxAttempts(2).initialDelay(500).build();
// after
ModelRetryInterceptor.builder().maxAttempts(5).initialDelay(1000).maxDelay(15000).backoffMultiplier(2.0).build();
Defensive patterns

Strategy: retry

Validate before calling

// Ensure sane retry budget before running
ModelRetryInterceptor.Builder b = ModelRetryInterceptor.builder();
assert b != null; // configure maxAttempts>=3, maxDelay>=10s for production traffic

Try / catch

try {
    return retryInterceptor.interceptModel(request, handler);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Model call failed, maximum number of retries reached. ")) {
        log.error("Retry budget exhausted ({} attempts); final cause: {}", e.getMessage(), e.getCause());
        return fallbackHandler.apply(request); // circuit-break / degrade
    }
    throw e;
}

Prevention

When it happens

Trigger: interceptModel where every attempt throws a retryable-predicate-passing exception and control flow exits the loop — logically equivalent to error 614 but reachable only if the final attempt's failure bypasses the earlier maxAttempts check.

Common situations: Sustained provider unavailability across the whole retry window; all attempts failing with retryable network errors (connection reset, timeout); retry budget too small relative to the outage duration.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/fea1463b40c0c462. Report an issue: GitHub.