in hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AUtils.java [173:374]
public static IOException translateException(@Nullable String operation,
@Nullable String path,
SdkException exception) {
String message = String.format("%s%s: %s",
operation,
StringUtils.isNotEmpty(path)? (" on " + path) : "",
exception);
if (path == null || path.isEmpty()) {
// handle null path by giving it a stub value.
// not ideal/informative, but ensures that the path is never null in
// exceptions constructed.
path = "/";
}
exception = maybeProcessEncryptionClientException(exception);
if (!(exception instanceof AwsServiceException)) {
// exceptions raised client-side: connectivity, auth, network problems...
Exception innerCause = containsInterruptedException(exception);
if (innerCause != null) {
// interrupted IO, or a socket exception underneath that class
return translateInterruptedException(exception, innerCause, message);
}
if (isMessageTranslatableToEOF(exception)) {
// call considered an sign of connectivity failure
return (EOFException)new EOFException(message).initCause(exception);
}
// if the exception came from the auditor, hand off translation
// to it.
IOException ioe = maybeTranslateAuditException(path, exception);
if (ioe != null) {
return ioe;
}
ioe = maybeTranslateCredentialException(path, exception);
if (ioe != null) {
return ioe;
}
// network problems covered by an IOE inside the exception chain.
ioe = maybeExtractIOException(path, exception, message);
if (ioe != null) {
return ioe;
}
// timeout issues
// ApiCallAttemptTimeoutException: a single HTTP request attempt failed.
// ApiCallTimeoutException: a request with any configured retries failed.
// The ApiCallTimeoutException exception should be the only one seen in
// the S3A code, but for due diligence both are handled and mapped to
// our own AWSApiCallTimeoutException.
if (exception instanceof ApiCallTimeoutException
|| exception instanceof ApiCallAttemptTimeoutException) {
// An API call to an AWS service timed out.
// This is a subclass of ConnectTimeoutException so
// all retry logic for that exception is handled without
// having to look down the stack for a
return new AWSApiCallTimeoutException(message, exception);
}
// no custom handling.
return new AWSClientIOException(message, exception);
} else {
// "error response returned by an S3 or other service."
// These contain more details and should be translated based
// on the HTTP status code and other details.
IOException ioe;
AwsServiceException ase = (AwsServiceException) exception;
// this exception is non-null if the service exception is an s3 one
S3Exception s3Exception = ase instanceof S3Exception
? (S3Exception) ase
: null;
int status = ase.statusCode();
if (ase.awsErrorDetails() != null) {
message = message + ":" + ase.awsErrorDetails().errorCode();
}
// big switch on the HTTP status code.
switch (status) {
case SC_301_MOVED_PERMANENTLY:
case SC_307_TEMPORARY_REDIRECT:
if (s3Exception != null) {
message = String.format("Received permanent redirect response to "
+ "region %s. This likely indicates that the S3 region "
+ "configured in %s does not match the AWS region containing " + "the bucket.",
s3Exception.awsErrorDetails().sdkHttpResponse().headers().get(BUCKET_REGION_HEADER),
AWS_REGION);
ioe = new AWSRedirectException(message, s3Exception);
} else {
ioe = new AWSRedirectException(message, ase);
}
break;
case SC_400_BAD_REQUEST:
ioe = new AWSBadRequestException(message, ase);
break;
// permissions
case SC_401_UNAUTHORIZED:
case SC_403_FORBIDDEN:
ioe = new AccessDeniedException(path, null, message);
ioe.initCause(ase);
break;
// the object isn't there
case SC_404_NOT_FOUND:
if (isUnknownBucket(ase)) {
// this is a missing bucket
ioe = new UnknownStoreException(path, message, ase);
} else {
// a normal unknown object.
// Can also be raised by third-party stores when aborting an unknown multipart upload
ioe = new FileNotFoundException(message);
ioe.initCause(ase);
}
break;
// Caused by duplicate create bucket call.
case SC_409_CONFLICT:
ioe = new AWSBadRequestException(message, ase);
break;
// this also surfaces sometimes and is considered to
// be ~ a not found exception.
case SC_410_GONE:
ioe = new FileNotFoundException(message);
ioe.initCause(ase);
break;
// errors which stores can return from requests which
// the store does not support.
case SC_405_METHOD_NOT_ALLOWED:
case SC_415_UNSUPPORTED_MEDIA_TYPE:
case SC_501_NOT_IMPLEMENTED:
ioe = new AWSUnsupportedFeatureException(message, ase);
break;
// precondition failure: the object is there, but the precondition
// (e.g. etag) didn't match. Assume remote file change during
// rename or status passed in to openfile had an etag which didn't match.
case SC_412_PRECONDITION_FAILED:
ioe = new RemoteFileChangedException(path, message, "", ase);
break;
// out of range. This may happen if an object is overwritten with
// a shorter one while it is being read or openFile() was invoked
// passing a FileStatus or file length less than that of the object.
// although the HTTP specification says that the response should
// include a range header specifying the actual range available,
// this isn't picked up here.
case SC_416_RANGE_NOT_SATISFIABLE:
ioe = new RangeNotSatisfiableEOFException(message, ase);
break;
// this has surfaced as a "no response from server" message.
// so rare we haven't replicated it.
// Treating as an idempotent proxy error.
case SC_443_NO_RESPONSE:
case SC_444_NO_RESPONSE:
ioe = new AWSNoResponseException(message, ase);
break;
// throttling
case SC_429_TOO_MANY_REQUESTS_GCS: // google cloud through this connector
case SC_503_SERVICE_UNAVAILABLE: // AWS
ioe = new AWSServiceThrottledException(message, ase);
break;
// gateway timeout
case SC_504_GATEWAY_TIMEOUT:
ioe = new AWSApiCallTimeoutException(message, ase);
break;
// internal error
case SC_500_INTERNAL_SERVER_ERROR:
ioe = new AWSStatus500Exception(message, ase);
break;
case SC_200_OK:
if (exception instanceof MultiObjectDeleteException) {
// failure during a bulk delete
return ((MultiObjectDeleteException) exception)
.translateException(message);
}
// other 200: FALL THROUGH
default:
// no specifically handled exit code.
// convert all unknown 500+ errors to a 500 exception
if (status > SC_500_INTERNAL_SERVER_ERROR) {
ioe = new AWSStatus500Exception(message, ase);
break;
}
// Choose an IOE subclass based on the class of the caught exception
ioe = s3Exception != null
? new AWSS3IOException(message, s3Exception)
: new AWSServiceIOException(message, ase);
break;
}
return ioe;
}
}