CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-ai--spring-ai-retry

Spring AI utility library providing retry mechanisms for AI API interactions with comprehensive error handling and exception classification

Overview
Eval results
Files

exception-reference.mddocs/reference/

Exception Reference

Complete exception reference for Spring AI Retry.

Exception Hierarchy

java.lang.RuntimeException
├── org.springframework.ai.retry.TransientAiException
└── org.springframework.ai.retry.NonTransientAiException

TransientAiException

Exception for transient failures that may succeed on retry.

public class TransientAiException extends RuntimeException

Package: org.springframework.ai.retry

Extends: java.lang.RuntimeException

Purpose: Represents AI service errors that are temporary and may succeed when retried without intervention.

Common Scenarios

  1. 5xx Server Errors

    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  2. Network Issues

    • Connection timeout
    • Connection reset
    • DNS resolution failures
    • Socket timeout
  3. Temporary Service States

    • Rate limiting (when temporary)
    • Service overload
    • Database connection pool exhausted
    • Circuit breaker open (temporary)
  4. Token Issues

    • Expired OAuth token (can be refreshed)
    • Temporary token service outage

Constructors

public TransientAiException(String message)

Creates a new transient exception with the specified message.

Parameters:

  • message - The error message describing the transient failure

Example:

throw new TransientAiException("AI service temporarily unavailable");

public TransientAiException(String message, Throwable cause)

Creates a new transient exception with the specified message and cause.

Parameters:

  • message - The error message describing the transient failure
  • cause - The underlying cause

Example:

try {
    response = httpClient.execute(request);
} catch (SocketTimeoutException e) {
    throw new TransientAiException("Connection timeout to AI service", e);
}

Inherited Methods

All methods from java.lang.RuntimeException:

  • getMessage() - Returns the detail message
  • getCause() - Returns the cause or null
  • getStackTrace() - Returns stack trace elements
  • printStackTrace() - Prints stack trace
  • toString() - Returns string representation

Usage Patterns

Pattern 1: Wrapping Service-Specific Exceptions

try {
    return aiClient.generate(prompt);
} catch (ServiceUnavailableException e) {
    throw new TransientAiException("AI service unavailable", e);
} catch (RateLimitException e) {
    throw new TransientAiException("Rate limit exceeded", e);
}

Pattern 2: Network Error Handling

try {
    return restTemplate.postForObject(url, request, String.class);
} catch (ResourceAccessException e) {
    // Already a transient exception in Spring, but can wrap
    throw new TransientAiException("Network error calling AI service", e);
}

Pattern 3: Conditional Transient Errors

if (circuitBreaker.isOpen()) {
    throw new TransientAiException("Circuit breaker open - service recovering");
}

Best Practices

  1. Always include descriptive messages that help diagnose the issue
  2. Include the underlying cause when wrapping other exceptions
  3. Use for errors that don't require code changes to fix
  4. Don't use for errors that require user intervention (use NonTransientAiException)
  5. Log at WARN level (vs ERROR for non-transient)

NonTransientAiException

Exception for permanent failures that should not be retried.

public class NonTransientAiException extends RuntimeException

Package: org.springframework.ai.retry

Extends: java.lang.RuntimeException

Purpose: Represents AI service errors that are permanent and will not succeed on retry unless the underlying cause is corrected.

Common Scenarios

  1. 4xx Client Errors

    • 400 Bad Request
    • 401 Unauthorized
    • 403 Forbidden
    • 404 Not Found
    • 422 Unprocessable Entity
  2. Authentication/Authorization

    • Invalid API key
    • Expired credentials (non-renewable)
    • Insufficient permissions
    • Account suspended
  3. Validation Errors

    • Malformed request body
    • Invalid parameters
    • Prompt too long
    • Unsupported model
  4. Resource Issues

    • Resource not found
    • Quota permanently exceeded
    • Unsupported operation
  5. Configuration Errors

    • Missing required configuration
    • Invalid endpoint URL
    • Unsupported content type

Constructors

public NonTransientAiException(String message)

Creates a new non-transient exception with the specified message.

Parameters:

  • message - The error message describing the permanent failure

Example:

throw new NonTransientAiException("Invalid API key");

public NonTransientAiException(String message, Throwable cause)

Creates a new non-transient exception with the specified message and cause.

Parameters:

  • message - The error message describing the permanent failure
  • cause - The underlying cause

Example:

try {
    request = objectMapper.readValue(json, Request.class);
} catch (JsonParseException e) {
    throw new NonTransientAiException("Invalid request format", e);
}

Inherited Methods

All methods from java.lang.RuntimeException:

  • getMessage() - Returns the detail message
  • getCause() - Returns the cause or null
  • getStackTrace() - Returns stack trace elements
  • printStackTrace() - Prints stack trace
  • toString() - Returns string representation

Usage Patterns

Pattern 1: Validation Errors

if (prompt == null || prompt.isEmpty()) {
    throw new NonTransientAiException("Prompt cannot be empty");
}

if (prompt.length() > MAX_PROMPT_LENGTH) {
    throw new NonTransientAiException(
        "Prompt exceeds maximum length of " + MAX_PROMPT_LENGTH);
}

Pattern 2: Authentication Errors

try {
    return aiClient.generate(prompt);
} catch (AuthenticationException e) {
    throw new NonTransientAiException("Invalid API credentials", e);
}

Pattern 3: Configuration Errors

if (apiKey == null) {
    throw new NonTransientAiException(
        "API key not configured - check application.properties");
}

if (!model.isSupported()) {
    throw new NonTransientAiException(
        "Unsupported model: " + model);
}

Best Practices

  1. Use for errors that require code or configuration changes
  2. Include specific guidance on how to fix the issue in the message
  3. Don't use for temporary issues like rate limits or service outages
  4. Propagate to callers rather than catching and ignoring
  5. Log at ERROR level (vs WARN for transient errors)

Error Classification Decision Tree

Is this a temporary failure that might succeed on retry?
│
├─ YES → Use TransientAiException
│  │
│  ├─ Network timeout/connection error
│  ├─ 5xx server error
│  ├─ Service overload/rate limit (temporary)
│  ├─ Circuit breaker open
│  └─ Renewable token expiration
│
└─ NO → Use NonTransientAiException
   │
   ├─ 4xx client error (except transient rate limits)
   ├─ Invalid API key/credentials
   ├─ Validation error
   ├─ Resource not found
   ├─ Configuration error
   └─ Permanent quota exceeded

Error Classification by HTTP Status

HTTP StatusDefault ExceptionRationale
400 Bad RequestNonTransientAiExceptionMalformed request won't fix itself
401 UnauthorizedNonTransientAiExceptionInvalid credentials need fixing
403 ForbiddenNonTransientAiExceptionInsufficient permissions
404 Not FoundNonTransientAiExceptionResource doesn't exist
429 Too Many RequestsNonTransientAiException*Usually rate limit (configure as transient if temporary)
500 Internal Server ErrorTransientAiExceptionTemporary server issue
502 Bad GatewayTransientAiExceptionUpstream service temporarily down
503 Service UnavailableTransientAiExceptionService temporarily overloaded
504 Gateway TimeoutTransientAiExceptionUpstream service timeout

* Default is non-transient, but can be configured as transient via spring.ai.retry.on-http-codes: [429]

Exception Handling Patterns

Pattern 1: Basic Catch and Handle

try {
    result = retryTemplate.execute(context -> aiClient.generate(prompt));
} catch (TransientAiException e) {
    // All retries exhausted - service is down
    logger.error("AI service unavailable after retries", e);
    throw new ServiceUnavailableException("AI service temporarily down", e);
} catch (NonTransientAiException e) {
    // Immediate failure - request is invalid
    logger.error("Invalid AI request", e);
    throw new BadRequestException("Unable to process request", e);
}

Pattern 2: With Recovery

try {
    result = retryTemplate.execute(
        context -> aiClient.generate(prompt),
        recoveryContext -> cacheService.getLastKnownGood(prompt)
    );
} catch (NonTransientAiException e) {
    // Non-transient errors bypass recovery
    throw new BadRequestException("Invalid request", e);
}

Pattern 3: Conditional Handling

try {
    result = retryTemplate.execute(context -> aiClient.generate(prompt));
} catch (TransientAiException e) {
    if (fallbackEnabled) {
        return fallbackService.generate(prompt);
    } else {
        throw new ServiceUnavailableException("Service down", e);
    }
} catch (NonTransientAiException e) {
    throw new BadRequestException("Invalid request", e);
}

Error Classification in Custom Code

Classify Network Errors

try {
    return httpClient.execute(request);
} catch (SocketTimeoutException e) {
    throw new TransientAiException("Connection timeout", e);
} catch (ConnectException e) {
    throw new TransientAiException("Connection refused", e);
} catch (UnknownHostException e) {
    throw new TransientAiException("DNS resolution failed", e);
}

Classify HTTP Errors

if (response.getStatusCode().is5xxServerError()) {
    throw new TransientAiException(
        "Server error: " + response.getStatusCode());
} else if (response.getStatusCode().is4xxClientError()) {
    throw new NonTransientAiException(
        "Client error: " + response.getStatusCode());
}

Classify Business Logic Errors

if (result.isQuotaExceeded()) {
    if (result.isTemporaryQuota()) {
        throw new TransientAiException("Temporary quota exceeded");
    } else {
        throw new NonTransientAiException("Monthly quota exceeded");
    }
}

Next Steps

  • API Reference - Complete API documentation
  • Error Handling Strategies - Comprehensive error handling examples
  • Edge Cases - Common pitfalls and edge cases

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-ai--spring-ai-retry@1.1.0

docs

index.md

tile.json