Error Handling & Exceptions
AWS SDKs expose errors as structured exceptions that surface the service code, HTTP status, request ID, and retry hints needed to classify and recover from failures.
Busca en todas las páginas de la documentación
AWS SDKs expose errors as structured exceptions that surface the service code, HTTP status, request ID, and retry hints needed to classify and recover from failures.
Wrap SDK operations in try-catch to capture service and network errors uniformly.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
import boto3
s3 = boto3.client("s3")
try:
s3.head_object(Bucket="my-bucket", Key="key")
except ClientError as e:
print(f"Error: {e}")// --- TypeScript (AWS SDK v3) ---
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
const client = new S3Client({});
try {
await client.send(
new HeadObjectCommand({ Bucket: "my-bucket", Key: "key" })
);
} catch (e) {
console.error("Error:", e);
}The service error code is the stable string to branch on for error recovery logic.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
try:
s3.head_object(Bucket="b", Key="missing")
except ClientError as e:
code = e.response["Error"]["Code"]
print(code) # NotFound// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new HeadObjectCommand({ Bucket: "b", Key: "missing" }));
} catch (e: any) {
const code = e.name; // NotFound
console.log(code);
}The HTTP status code indicates the class of error (4xx client, 5xx server).
# --- Python (boto3) ---
try:
s3.head_object(Bucket="b", Key="k")
except ClientError as e:
status = e.response["ResponseMetadata"]["HTTPStatusCode"]
print(status) # 404// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new HeadObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e: any) {
const status = e.$metadata?.httpStatusCode;
console.log(status); // 404
}Service SDKs expose typed exception classes for common errors to enable precise error handling.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
try:
s3.get_object(Bucket="b", Key="missing")
except s3.exceptions.NoSuchKey as e:
print("Key not found")
except ClientError as e:
print(f"Other error: {e}")// --- TypeScript (AWS SDK v3) ---
import { NoSuchKey } from "@aws-sdk/client-s3";
try {
await s3.send(new GetObjectCommand({ Bucket: "b", Key: "missing" }));
} catch (e) {
if (e instanceof NoSuchKey) {
console.log("Key not found");
} else {
console.error("Other error:", e);
}
}The request ID from response metadata is essential for AWS support investigations.
# --- Python (boto3) ---
try:
s3.get_object(Bucket="b", Key="k")
except ClientError as e:
req_id = e.response["ResponseMetadata"]["RequestId"]
print(f"Support ticket: {req_id}")// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e: any) {
const reqId = e.$metadata?.requestId;
console.log(`Support ticket: ${reqId}`);
}Throttling errors (rate limits) are retryable; the SDK may auto-retry, but check metadata for manual handling.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
try:
dynamodb.put_item(TableName="t", Item={})
except ClientError as e:
code = e.response["Error"]["Code"]
is_throttled = code in ["ProvisionedThroughputExceededException", "ThrottlingException"]
if is_throttled:
print("Throttled; retry after backoff")// --- TypeScript (AWS SDK v3) ---
try {
await dynamodb.send(new PutItemCommand({ TableName: "t", Item: {} }));
} catch (e: any) {
const isThrottled = e.$retryable === true;
if (isThrottled) {
console.log("Throttled; retry after backoff");
}
}AccessDenied errors (4xx auth failures) signal insufficient permissions and are not retryable.
# --- Python (boto3) ---
try:
s3.get_object(Bucket="restricted", Key="k")
except ClientError as e:
if e.response["Error"]["Code"] == "AccessDenied":
print("Insufficient permissions; check IAM policy")
else:
raise// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new GetObjectCommand({ Bucket: "restricted", Key: "k" }));
} catch (e: any) {
if (e.name === "AccessDenied") {
console.log("Insufficient permissions; check IAM policy");
} else {
throw e;
}
}ConditionalCheckFailed occurs when a conditional write (e.g. put_item with ConditionExpression) fails validation.
# --- Python (boto3) ---
try:
dynamodb.put_item(
TableName="t",
Item={"id": {"S": "1"}},
ConditionExpression="attribute_not_exists(id)"
)
except ClientError as e:
if e.response["Error"]["Code"] == "ConditionalCheckFailedException":
print("Item already exists")// --- TypeScript (AWS SDK v3) ---
try {
await dynamodb.send(new PutItemCommand({
TableName: "t",
Item: { id: { S: "1" } },
ConditionExpression: "attribute_not_exists(id)"
}));
} catch (e: any) {
if (e.name === "ConditionalCheckFailedException") {
console.log("Item already exists");
}
}ResourceNotFound (404) indicates the resource does not exist; recovery depends on whether creation is safe.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
try:
ec2.describe_instances(InstanceIds=["i-notfound"])
except ClientError as e:
if "InvalidInstanceID.NotFound" in e.response["Error"]["Code"]:
print("Instance does not exist")
else:
raise// --- TypeScript (AWS SDK v3) ---
try {
await ec2.send(
new DescribeInstancesCommand({ InstanceIds: ["i-notfound"] })
);
} catch (e: any) {
if (e.name.includes("NotFound") || e.name.includes("InvalidInstanceID")) {
console.log("Instance does not exist");
} else {
throw e;
}
}Validation errors (e.g. invalid enum value, missing required field) are client-side and non-retryable.
# --- Python (boto3) ---
from botocore.exceptions import ParamValidationError
try:
s3.get_object(Bucket="", Key="k") # Empty bucket
except ParamValidationError as e:
print(f"Invalid parameter: {e}")// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new GetObjectCommand({ Bucket: "", Key: "k" }));
} catch (e: any) {
if (e.name === "ValidationException") {
console.log(`Invalid parameter: ${e.message}`);
} else {
throw e;
}
}Safely retry only GET, HEAD, and other idempotent reads; avoid auto-retry on write failures (create, delete) unless you verify idempotency.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
def safe_retry_get(key, max_retries=3):
for attempt in range(max_retries):
try:
return s3.get_object(Bucket="b", Key=key)
except ClientError as e:
if attempt == max_retries - 1:
raise
if e.response["Error"]["Code"] in ["ThrottlingException", "RequestTimeout"]:
continue// --- TypeScript (AWS SDK v3) ---
async function safeRetryGet(key: string, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await s3.send(new GetObjectCommand({ Bucket: "b", Key: key }));
} catch (e: any) {
if (attempt === maxRetries - 1) throw e;
if (["ThrottlingException", "RequestTimeout"].includes(e.name)) continue;
}
}
}Timeout errors indicate the operation took too long; connection errors indicate network issues. Both are typically retryable.
# --- Python (boto3) ---
from botocore.exceptions import ClientError, ConnectTimeoutError, ReadTimeoutError
try:
s3.get_object(Bucket="b", Key="k")
except ConnectTimeoutError:
print("Connection timeout; check network")
except ReadTimeoutError:
print("Read timeout; request took too long")
except ClientError as e:
print(f"Other error: {e}")// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e: any) {
if (e.name === "ConnectTimeoutError") {
console.log("Connection timeout; check network");
} else if (e.name === "ReadTimeoutError") {
console.log("Read timeout; request took too long");
} else {
console.error("Other error:", e);
}
}Structured logging with error details aids debugging and monitoring.
# --- Python (boto3) ---
import json
from botocore.exceptions import ClientError
try:
s3.get_object(Bucket="b", Key="k")
except ClientError as e:
log_entry = {
"error_code": e.response["Error"]["Code"],
"http_status": e.response["ResponseMetadata"]["HTTPStatusCode"],
"request_id": e.response["ResponseMetadata"]["RequestId"],
"message": e.response["Error"]["Message"]
}
print(json.dumps(log_entry))// --- TypeScript (AWS SDK v3) ---
try {
await s3.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e: any) {
const logEntry = {
errorCode: e.name,
httpStatus: e.$metadata?.httpStatusCode,
requestId: e.$metadata?.requestId,
message: e.message
};
console.log(JSON.stringify(logEntry));
}Encapsulate SDK errors in domain-specific exceptions for cleaner API boundaries and better error context.
# --- Python (boto3) ---
class StorageError(Exception):
def __init__(self, message, code, request_id):
self.code = code
self.request_id = request_id
super().__init__(message)
try:
s3.get_object(Bucket="b", Key="k")
except ClientError as e:
raise StorageError(
f"Failed to fetch object: {e.response['Error']['Message']}",
e.response["Error"]["Code"],
e.response["ResponseMetadata"]["RequestId"]
)// --- TypeScript (AWS SDK v3) ---
class StorageError extends Error {
constructor(
message: string,
public code: string,
public requestId?: string
) {
super(message);
this.name = "StorageError";
}
}
try {
await s3.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e: any) {
throw new StorageError(
`Failed to fetch object: ${e.message}`,
e.name,
e.$metadata?.requestId
);
}Unit tests verify error handling by checking the error code and HTTP status.
# --- Python (boto3) ---
import pytest
from botocore.exceptions import ClientError
def test_missing_key_raises():
with pytest.raises(ClientError) as exc_info:
s3.get_object(Bucket="b", Key="missing")
assert exc_info.value.response["Error"]["Code"] == "NoSuchKey"
assert exc_info.value.response["ResponseMetadata"]["HTTPStatusCode"] == 404// --- TypeScript (AWS SDK v3) ---
import { test, expect } from "@jest/globals";
import { NoSuchKey } from "@aws-sdk/client-s3";
test("missing key raises NoSuchKey", async () => {
try {
await s3.send(new GetObjectCommand({ Bucket: "b", Key: "missing" }));
throw new Error("Should have thrown");
} catch (e: any) {
expect(e instanceof NoSuchKey).toBe(true);
expect(e.$metadata?.httpStatusCode).toBe(404);
}
});Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Revisado por Chris St. John·Última actualización: 23 jul 2026