alibaba/spring-ai-alibaba · warning · RuntimeException
Retry interrupted
Error message
Retry interrupted
What it means
During ModelRetryInterceptor's blocking backoff (Thread.sleep between non-streaming attempts), the thread was interrupted while sleeping. The interceptor restores the interrupt flag and rethrows RuntimeException("Retry interrupted", e) to abort the retry loop promptly.
Source
Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/interceptor/modelretry/ModelRetryInterceptor.java:107
return modelResponse;
}
// Check if the response contains any exception information (exceptions captured from AgentLlmNode).
if (message != null && message.getText() != null && message.getText().startsWith("Exception:")) {
String exceptionText = message.getText();
log.warn("The model call returned an exception message: {}", exceptionText);
// Extract anomaly information from the text and determine whether a retry is possible.
if (attempt < maxAttempts && isRetryableExceptionMessage(exceptionText)) {
lastException = new RuntimeException(exceptionText);
// Wait and try again
if (currentDelay > 0) {
try {
log.info("Retry after {} ms", currentDelay);
Thread.sleep(currentDelay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("Retry interrupted", e);
}
}
// Calculate the next delay time (exponential backoff)
currentDelay = Math.min((long) (currentDelay * backoffMultiplier), maxDelay);
continue;
} else if (attempt >= maxAttempts) {
log.error("The maximum number of retries has been reached {}, and the model call has failed.", maxAttempts);
throw new RuntimeException("Model call failed, maximum number of retries reached:" + exceptionText);
}
// For non-retryable exceptions, return immediately.
return modelResponse;
}
// Successful response
if (attempt > 1) {
log.info("The model call succeeded after the {}th attempt.", attempt);
}View on GitHub (pinned to f82da0b50f)
Solutions
- Treat this as intentional cancellation: catch RuntimeException, check that getCause() instanceof InterruptedException, and stop the work rather than retrying further.
- Check the interrupt flag (Thread.currentThread().isInterrupted()) around long agent runs and shut down gracefully before killing pools.
- Reduce initialDelay/maxDelay so backoff sleeps are short and less likely to straddle shutdown windows.
- If interruption is unexpected, audit which code calls interrupt()/shutdownNow() on the executing thread pool.
Defensive patterns
Strategy: try-catch
Try / catch
try {
return retryInterceptor.interceptModel(request, handler);
} catch (RuntimeException e) {
if ("Retry interrupted".equals(e.getMessage()) && e.getCause() instanceof InterruptedException) {
Thread.currentThread().interrupt(); // preserve flag if re-entering interruptible code
throw new CancellationException("Model retry cancelled");
}
throw e;
} Prevention
- Avoid shutdownNow()/Future.cancel(true) on threads running agent calls; drain pools gracefully.
- Keep backoff delays small so sleeps rarely overlap shutdown windows.
- Check Thread.interrupted() status before launching long agent runs.
When it happens
Trigger: interceptModel sleeping in the retry delay path (a retryable 'Exception:' message in the response, attempt < maxAttempts, currentDelay > 0) when the executing thread receives Thread.interrupt() — typically task cancellation, executor shutdown, or a timeout wrapper cancelling the call.
Common situations: Application shutdown or Spring context close while an agent call is mid-backoff; @Timed/timeout frameworks interrupting long-running calls; cancelling a Future or shutting down the thread pool running the agent graph.
Related errors
- Retry interrupted
- The backoffMultiplier must be >= 1.0
- maxRetries must be >= 0
- Retry interrupted
- Tool '{}' failed (attempt {}/{}), retrying in {}ms: {}
AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09).
Data as JSON: /api/errors/cdd7a0b1d86b05d3.
Report an issue: GitHub.