Error Handling & Retry Rules Checklist
A remote call fails differently from a local one. It throttles, times out, and fails transiently over the network.
Search across all documentation pages
A remote call fails differently from a local one. It throttles, times out, and fails transiently over the network.
This checklist covers which errors to catch, which operations are safe to retry, and how to bound the retries so a blip does not become an outage or a bill.
ClientError in boto3 and typed exception classes in SDK v3 rather than a broad except Exception / catch (e).err.response["Error"]["Code"] in boto3 and error.name in SDK v3, then decide per code.Match the specific error and read its code.
# --- Python (boto3) ---
from botocore.exceptions import ClientError
try:
obj = s3.get_object(Bucket="reports", Key="q3.csv")
except ClientError as err:
code = err.response["Error"]["Code"]
if code == "NoSuchKey":
obj = default_report() # known, recoverable
else:
raise # surface the rest// --- TypeScript (AWS SDK v3) ---
import { GetObjectCommand, NoSuchKey } from "@aws-sdk/client-s3";
try {
var obj = await s3.send(new GetObjectCommand({ Bucket: "reports", Key: "q3.csv" }));
} catch (err) {
if (err instanceof NoSuchKey) obj = defaultReport(); // known, recoverable
else throw err; // surface the rest
}ThrottlingException, TooManyRequestsException, and ProvisionedThroughputExceededException are transient and should back off and retry.InternalError, ServiceUnavailable, timeouts, and connection resets are retryable.ValidationException, InvalidParameterValue, and similar 4xx errors will fail identically every time; fix the input.AccessDenied and UnrecognizedClient mean permissions or credentials, not a transient blip.ConditionalCheckFailedException is a business outcome to handle, not a call to retry.Get, List, Describe, and Head operations are naturally idempotent and safe to retry.SendMessage or Publish can create duplicates unless made idempotent.ClientRequestToken / clientToken so a retried create is deduplicated by the service.ConditionExpression (DynamoDB) or If-Match (S3) makes a repeated write a no-op instead of a double-apply.Pass an idempotency token so a retried create does not duplicate the resource.
# --- Python (boto3) ---
import uuid, boto3
sqs = boto3.client("sqs", region_name="us-east-1")
token = str(uuid.uuid4()) # stable across retries of THIS logical send
sqs.send_message(
QueueUrl=queue_url,
MessageBody="order-42",
MessageDeduplicationId=token, # FIFO queue dedupes retried sends
MessageGroupId="orders",
)// --- TypeScript (AWS SDK v3) ---
import { randomUUID } from "node:crypto";
import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";
const sqs = new SQSClient({ region: "us-east-1" });
const token = randomUUID(); // stable across retries of THIS logical send
await sqs.send(new SendMessageCommand({
QueueUrl: queueUrl,
MessageBody: "order-42",
MessageDeduplicationId: token, // FIFO queue dedupes retried sends
MessageGroupId: "orders",
}));Config(retries={"max_attempts": N}) in boto3 or maxAttempts: N in SDK v3; never retry an unbounded number of times.Configure retry behavior on the client, not in an ad-hoc loop.
# --- Python (boto3) ---
import boto3
from botocore.config import Config
cfg = Config(retries={"max_attempts": 5, "mode": "adaptive"})
ddb = boto3.client("dynamodb", region_name="us-east-1", config=cfg)// --- TypeScript (AWS SDK v3) ---
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
// maxAttempts caps total tries (1 initial + retries); adaptive mode adds rate limiting.
const ddb = new DynamoDBClient({ region: "us-east-1", maxAttempts: 5 });ResponseMetadata.RequestId (boto3) or $metadata.requestId (SDK v3) so AWS support can trace the call.In boto3, catch ClientError and read err.response["Error"]["Code"]. In SDK v3, match typed exception classes with instanceof, or branch on error.name.
Throttling errors and transient 5xx or network errors. Validation, access-denied, and conditional-check failures are terminal and will fail the same way again.
Because a retried write can duplicate work. An idempotency token or conditional write lets the service recognize the repeat and apply it only once.
Usually not. Both SDKs retry transient failures with backoff by default. Configure max_attempts / maxAttempts and a retry mode instead of hand-rolling a loop.
A retry mode that adds client-side rate limiting on top of standard exponential backoff, which helps when a service is throttling you under sustained load.
An unbounded retry loop hammers the API. Each attempt is billed and adds load, so a transient error that should cost one call can cost many.
Only at a top-level boundary to convert an unexpected failure into a clean response. Business logic should catch the specific typed error and re-raise the rest.
It uniquely identifies the call on the AWS side. When you open a support case or chase an intermittent failure, the request id is what lets AWS trace it.
Pass a client request token (a stable UUID for the logical operation). If the create is retried, the service deduplicates on the token instead of creating twice.
Connect and read timeouts short enough that a hung socket fails within your latency budget, leaving room for the SDK to retry before the caller gives up.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 23, 2026