CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-amazonaws--aws-java-sdk-core

Core foundational library for AWS SDK for Java 1.x providing authentication, HTTP transport, regions, protocols, and shared utilities for all AWS service clients

Pending
Overview
Eval results
Files

exception-handling.mddocs/

Exception Handling & Error Management

The AWS Java SDK Core provides a comprehensive exception hierarchy for handling different types of errors that can occur during AWS service interactions. Understanding this hierarchy is crucial for proper error handling and application resilience.

Exception Hierarchy

Base Exception Classes

// Base SDK exception class (extends RuntimeException)
class SdkBaseException extends RuntimeException {
    public SdkBaseException(String message);
    public SdkBaseException(String message, Throwable cause);
    public boolean isRetryable();
}

// Client-side exception (network, configuration, etc.)
class SdkClientException extends SdkBaseException {
    public SdkClientException(String message);
    public SdkClientException(String message, Throwable cause);
    public boolean isRetryable();
}

// Legacy client exception (for backward compatibility)
class AmazonClientException extends SdkBaseException {
    public AmazonClientException(String message);
    public AmazonClientException(String message, Throwable cause);
    public AmazonClientException(Throwable cause);
    public boolean isRetryable();
}

Service Exception Classes

// Service-side exception (4xx/5xx HTTP responses)
class AmazonServiceException extends SdkClientException {
    // Error details
    public String getErrorCode();
    public String getErrorMessage();
    public String getErrorType();  
    public int getStatusCode();
    public String getServiceName();
    public String getRequestId();
    
    // Request details
    public String getRawResponseContent();
    public HttpResponse getRawResponse();
    public Map<String, String> getHttpHeaders();
    public String getProxyHost();
    
    // Error classification
    public ErrorType getErrorType();  
    public boolean isRetryable();
    
    // Setters for error details
    public void setErrorCode(String errorCode);
    public void setErrorMessage(String errorMessage);
    public void setErrorType(String errorType);
    public void setStatusCode(int statusCode);
    public void setServiceName(String serviceName);
    public void setRequestId(String requestId);
}

// Error type enumeration
enum ErrorType {
    Client,    // 4xx errors - client-side issues
    Service,   // 5xx errors - server-side issues
    Unknown    // Unclassified errors
}

Specific Exception Types

// Operation aborted exception
class AbortedException extends SdkClientException {
    public AbortedException();
    public AbortedException(String message);
    public AbortedException(String message, Throwable cause);
}

// Stream reset exception
class ResetException extends SdkClientException {
    public ResetException(String message);
    public ResetException(String message, Throwable cause);
    
    public String getExtraInfo();
    public void setExtraInfo(String extraInfo);
}

// Connection timeout exception
class SdkInterruptedException extends SdkClientException {
    public SdkInterruptedException(Throwable cause);
    public SdkInterruptedException(String message, Throwable cause);
}

Error Handling Patterns

Basic Exception Handling

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GetObjectRequest;

public void handleS3Operations(AmazonS3 s3Client, String bucket, String key) {
    try {
        // Perform S3 operation
        s3Client.getObject(new GetObjectRequest(bucket, key));
        
    } catch (AmazonServiceException ase) {
        // Service-side error (4xx/5xx HTTP status codes)
        System.err.println("Service Error:");
        System.err.println("  Error Code: " + ase.getErrorCode());
        System.err.println("  Error Message: " + ase.getErrorMessage());
        System.err.println("  HTTP Status: " + ase.getStatusCode());
        System.err.println("  Service: " + ase.getServiceName());
        System.err.println("  Request ID: " + ase.getRequestId());
        
        // Handle specific service errors
        handleServiceError(ase);
        
    } catch (SdkClientException ace) {
        // Client-side error (network issues, configuration problems, etc.)
        System.err.println("Client Error: " + ace.getMessage());
        
        // Handle client errors
        handleClientError(ace);
        
    } catch (Exception e) {
        // Unexpected errors
        System.err.println("Unexpected error: " + e.getMessage());
        throw new RuntimeException("Operation failed", e);
    }
}

Service Error Handling by Type

private void handleServiceError(AmazonServiceException ase) {
    // Handle errors by HTTP status code
    switch (ase.getStatusCode()) {
        case 400: // Bad Request
            handleBadRequestError(ase);
            break;
        case 403: // Forbidden
            handlePermissionError(ase);
            break;
        case 404: // Not Found
            handleNotFoundError(ase);
            break;
        case 429: // Too Many Requests
            handleThrottlingError(ase);
            break;
        case 500: // Internal Server Error
        case 502: // Bad Gateway  
        case 503: // Service Unavailable
            handleServerError(ase);
            break;
        default:
            handleUnknownServiceError(ase);
    }
    
    // Handle errors by error code (service-specific)
    String errorCode = ase.getErrorCode();
    switch (errorCode) {
        case "NoSuchBucket":
            System.err.println("S3 bucket does not exist");
            break;
        case "NoSuchKey":
            System.err.println("S3 object does not exist");
            break;
        case "AccessDenied":
            System.err.println("Access denied - check permissions");
            break;
        case "InvalidBucketName":
            System.err.println("Invalid S3 bucket name");
            break;
        case "ServiceUnavailable":
            System.err.println("Service temporarily unavailable");
            break;
        default:
            System.err.println("Service error: " + errorCode);
    }
}

Client Error Handling

private void handleClientError(SdkClientException ace) {
    // Check for specific client error types
    if (ace instanceof AbortedException) {
        System.err.println("Operation was aborted");
        // Handle abortion scenario
        
    } else if (ace instanceof ResetException) {
        ResetException re = (ResetException) ace;
        System.err.println("Connection reset: " + re.getExtraInfo());
        // Handle connection reset
        
    } else if (ace instanceof SdkInterruptedException) {
        System.err.println("Operation was interrupted");
        // Handle interruption
        
    } else {
        // Generic client error handling
        String message = ace.getMessage();
        
        if (message.contains("UnknownHostException")) {
            System.err.println("Network connectivity issue - check DNS/Internet connection");
            
        } else if (message.contains("ConnectTimeoutException")) {
            System.err.println("Connection timeout - service may be unavailable");
            
        } else if (message.contains("SocketTimeoutException")) {
            System.err.println("Socket timeout - operation took too long");
            
        } else if (message.contains("SSLException")) {
            System.err.println("SSL/TLS error - check certificates and protocol");
            
        } else {
            System.err.println("Client configuration or network error: " + message);
        }
    }
}

Retry Strategy with Exception Handling

Intelligent Retry Logic

import com.amazonaws.retry.RetryUtils;
import java.util.concurrent.TimeUnit;

public class ResilientAwsOperations {
    private static final int MAX_RETRIES = 3;
    private static final long INITIAL_BACKOFF_MS = 1000;
    
    public <T> T executeWithRetry(Supplier<T> operation) {
        int attempt = 0;
        Exception lastException = null;
        
        while (attempt < MAX_RETRIES) {
            try {
                return operation.get();
                
            } catch (AmazonServiceException ase) {
                lastException = ase;
                
                // Check if error is retryable
                if (shouldRetryServiceException(ase)) {
                    attempt++;
                    if (attempt < MAX_RETRIES) {
                        waitWithBackoff(attempt);
                        continue;
                    }
                }
                // Non-retryable service error
                throw ase;
                
            } catch (SdkClientException ace) {
                lastException = ace;
                
                // Check if client error is retryable
                if (shouldRetryClientException(ace)) {
                    attempt++;
                    if (attempt < MAX_RETRIES) {
                        waitWithBackoff(attempt);
                        continue;
                    }
                }
                // Non-retryable client error
                throw ace;
            }
        }
        
        // Max retries exceeded
        throw new RuntimeException("Max retries exceeded", lastException);
    }
    
    private boolean shouldRetryServiceException(AmazonServiceException ase) {
        // Retry on server errors (5xx)
        if (ase.getStatusCode() >= 500) {
            return true;
        }
        
        // Retry on throttling (429)
        if (ase.getStatusCode() == 429) {
            return true;
        }
        
        // Retry on specific error codes
        String errorCode = ase.getErrorCode();
        return "ServiceUnavailable".equals(errorCode) ||
               "Throttling".equals(errorCode) ||
               "ThrottlingException".equals(errorCode) ||
               "RequestTimeout".equals(errorCode);
    }
    
    private boolean shouldRetryClientException(SdkClientException ace) {
        String message = ace.getMessage().toLowerCase();
        
        // Retry on network-related errors
        return message.contains("connecttimeoutexception") ||
               message.contains("sockettimeoutexception") ||
               message.contains("connection reset") ||
               message.contains("connection refused") ||
               ace instanceof ResetException;
    }
    
    private void waitWithBackoff(int attempt) {
        long backoffMs = INITIAL_BACKOFF_MS * (1L << (attempt - 1)); // Exponential backoff
        try {
            TimeUnit.MILLISECONDS.sleep(backoffMs);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new SdkInterruptedException("Interrupted during backoff", e);
        }
    }
}

Usage of Retry Logic

ResilientAwsOperations resilientOps = new ResilientAwsOperations();

// Retry S3 operations
S3Object result = resilientOps.executeWithRetry(() -> 
    s3Client.getObject("my-bucket", "my-key")
);

// Retry DynamoDB operations
GetItemResult dynamoResult = resilientOps.executeWithRetry(() -> 
    dynamoClient.getItem("my-table", key)
);

Error Logging and Monitoring

Structured Error Logging

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class AwsErrorLogger {
    private static final Logger logger = LoggerFactory.getLogger(AwsErrorLogger.class);
    
    public static void logServiceException(AmazonServiceException ase, String operation) {
        try {
            // Add context to MDC
            MDC.put("aws.service", ase.getServiceName());
            MDC.put("aws.errorCode", ase.getErrorCode());
            MDC.put("aws.requestId", ase.getRequestId());
            MDC.put("aws.statusCode", String.valueOf(ase.getStatusCode()));
            MDC.put("operation", operation);
            
            // Log based on error severity
            if (ase.getStatusCode() >= 500) {
                logger.error("AWS service error: {} - {}", ase.getErrorCode(), ase.getErrorMessage(), ase);
            } else {
                logger.warn("AWS client error: {} - {}", ase.getErrorCode(), ase.getErrorMessage());
            }
            
        } finally {
            MDC.clear();
        }
    }
    
    public static void logClientException(SdkClientException ace, String operation) {
        try {
            MDC.put("operation", operation);
            MDC.put("exceptionType", ace.getClass().getSimpleName());
            
            logger.error("AWS client error during {}: {}", operation, ace.getMessage(), ace);
            
        } finally {
            MDC.clear();
        }
    }
}

Metrics Collection

import com.amazonaws.metrics.RequestMetricCollector;
import java.util.concurrent.atomic.AtomicLong;

public class ErrorMetricsCollector extends RequestMetricCollector {
    private final AtomicLong clientErrors = new AtomicLong();
    private final AtomicLong serviceErrors = new AtomicLong();
    private final AtomicLong throttlingErrors = new AtomicLong();
    
    @Override
    public void collectMetrics(Request<?> request, Response<?> response, Exception exception) {
        if (exception instanceof AmazonServiceException) {
            AmazonServiceException ase = (AmazonServiceException) exception;
            serviceErrors.incrementAndGet();
            
            if (ase.getStatusCode() == 429 || "Throttling".equals(ase.getErrorCode())) {
                throttlingErrors.incrementAndGet();
            }
            
            // Log metrics
            logger.info("Service error metrics - Total: {}, Throttling: {}", 
                       serviceErrors.get(), throttlingErrors.get());
                       
        } else if (exception instanceof SdkClientException) {
            clientErrors.incrementAndGet();
            
            logger.info("Client error metrics - Total: {}", clientErrors.get());
        }
    }
    
    // Expose metrics for monitoring systems
    public long getClientErrorCount() { return clientErrors.get(); }
    public long getServiceErrorCount() { return serviceErrors.get(); }
    public long getThrottlingErrorCount() { return throttlingErrors.get(); }
}

Error Recovery Strategies

Circuit Breaker Pattern

public class AwsCircuitBreaker {
    private enum State { CLOSED, OPEN, HALF_OPEN }
    
    private volatile State state = State.CLOSED;
    private volatile long lastFailureTime;
    private volatile int failureCount;
    
    private final int failureThreshold;
    private final long timeoutMs;
    
    public AwsCircuitBreaker(int failureThreshold, long timeoutMs) {
        this.failureThreshold = failureThreshold;
        this.timeoutMs = timeoutMs;
    }
    
    public <T> T execute(Supplier<T> operation) throws Exception {
        if (state == State.OPEN) {
            if (System.currentTimeMillis() - lastFailureTime > timeoutMs) {
                state = State.HALF_OPEN;
            } else {
                throw new RuntimeException("Circuit breaker is OPEN");
            }
        }
        
        try {
            T result = operation.get();
            onSuccess();
            return result;
            
        } catch (Exception e) {
            onFailure();
            throw e;
        }
    }
    
    private void onSuccess() {
        failureCount = 0;
        state = State.CLOSED;
    }
    
    private void onFailure() {
        failureCount++;
        lastFailureTime = System.currentTimeMillis();
        
        if (failureCount >= failureThreshold) {
            state = State.OPEN;
        }
    }
}

Fallback Mechanisms

public class FallbackAwsOperations {
    private final AmazonS3 primaryS3Client;
    private final AmazonS3 fallbackS3Client;
    
    public FallbackAwsOperations(AmazonS3 primary, AmazonS3 fallback) {
        this.primaryS3Client = primary;
        this.fallbackS3Client = fallback;
    }
    
    public S3Object getObjectWithFallback(String bucket, String key) {
        try {
            return primaryS3Client.getObject(bucket, key);
            
        } catch (AmazonServiceException ase) {
            if (ase.getStatusCode() >= 500) {
                logger.warn("Primary S3 service error, trying fallback: {}", ase.getErrorCode());
                return fallbackS3Client.getObject(bucket, key);
            }
            throw ase;
            
        } catch (SdkClientException ace) {
            logger.warn("Primary S3 client error, trying fallback: {}", ace.getMessage());
            return fallbackS3Client.getObject(bucket, key);
        }
    }
}

Best Practices

Exception Handling Best Practices

  1. Always catch specific exceptions first - Handle AmazonServiceException before SdkClientException
  2. Log error details comprehensively - Include error codes, request IDs, and HTTP status codes
  3. Implement appropriate retry logic - Use exponential backoff for retryable errors
  4. Don't ignore client exceptions - They often indicate configuration or network issues
  5. Use structured logging - Include operation context and error metadata

Error Recovery Best Practices

  1. Implement circuit breakers for external service calls
  2. Use fallback mechanisms where appropriate
  3. Monitor error rates and patterns for proactive issue detection
  4. Test error scenarios in development and staging environments
  5. Document error handling strategies for operations teams

Performance Considerations

  1. Avoid excessive retries on non-retryable errors
  2. Use appropriate timeout configurations to prevent hanging operations
  3. Consider async patterns for better resource utilization during retries
  4. Cache error classifications to avoid repeated error type checking

The AWS Java SDK's exception hierarchy provides the foundation for building resilient applications that can gracefully handle the various error conditions that occur in distributed cloud environments.

Install with Tessl CLI

npx tessl i tessl/maven-com-amazonaws--aws-java-sdk-core

docs

arn-support.md

authentication.md

client-builders.md

endpoint-discovery.md

exception-handling.md

http-transport.md

index.md

metrics-monitoring.md

protocols.md

regions-endpoints.md

retry-policies.md

utilities.md

waiters.md

tile.json