View a markdown version of this page

Retries - AWS SDK for Python

Developer Preview — This documentation covers the AWS SDK for Python, which is in Developer Preview and intended for evaluation and testing only. Do not use it for production workloads. For production applications, use the AWS SDK for Python (Boto3). To understand the differences between the two SDKs, see Choosing the right AWS SDK for Python.

Retries

This page explains how the SDK retries failed requests and how to configure retry behavior. It includes the following topics:

Calls to AWS services occasionally fail for reasons that have nothing to do with your request being wrong. A connection drops, a host is briefly unhealthy, or the service throttles you because too many requests arrived at the same time. Errors of this kind are often successful if the call is simply made again after a short delay, so every client in this SDK retries them automatically. This page explains how that retry behavior works and how to configure it.

Retryable errors

Only errors that are plausibly transient are retried. These include socket-level failures where no HTTP response was received (connect timeouts, read timeouts, or server-closed connections), HTTP 500, 502, 503, and 504 responses, and a set of service error codes the SDK recognizes as transient or throttling. Errors that signal a problem with the request itself like validation errors, missing or malformed parameters, authentication and authorization failures, and resource-not-found responses are never retried, because sending the same request again cannot change the outcome. Services can also mark their own exceptions as retryable in their service model, and the SDK honors that in addition to the built-in list.

Standard retry strategy

The standard retry strategy is the default. It makes a maximum of 3 attempts for a single request, including the initial attempt. This means a request is retried up to 2 times. Each retry is delayed using exponential backoff with jitter. The strategy also maintains a retry quota that prevents additional attempts when retries keep failing.

Backoff header: x-amz-retry-after

If a response carries an x-amz-retry-after header, the SDK incorporates it into the backoff calculation. The value is an integer number of milliseconds. If it is shorter than the computed delay, the SDK waits the computed delay; if it is longer than the computed delay plus 5 seconds, the SDK waits the computed delay plus 5 seconds. It is not jittered, and the 20-second maximum delay does not apply to it. Invalid values (such as invalid format or exceeding integer limits) specified in x-amz-retry-after are ignored and the SDK falls back to exponential backoff. The standard HTTP Retry-After header is ignored.

Calculating exponential backoff and retry quotas

The base delay doubles with every retry and is capped at 20 seconds. That delay is then multiplied by a random value between 0 and 1. The base delay is 1 second for throttling errors and 50 milliseconds for all other retryable errors. A transient error is therefore retried after up to 50ms, then up to 100ms, while a throttling error is retried after up to 1 second, then up to 2 seconds. DynamoDB and DynamoDB Streams clients make 4 attempts and use a base delay of 25 milliseconds for non-throttling errors.

The retry quota is a token bucket held per client. Each retry must take tokens from the bucket, and if the bucket does not have enough, the SDK returns the error without retrying. The bucket holds 500 tokens. A retry costs 14 tokens after a non-throttling error and 5 after a throttling error; a successful operation returns what its retry consumed, and an operation that succeeds without retrying adds 1 token, up to the 500-token maximum. When the bucket cannot cover the next retry, the SDK raises the error immediately without retrying. The first attempt is always made, only retries are affected.

Summary: retry strategy default values

The following table shows the default values for the properties of the standard retry strategy.

Property Default value
Maximum attempts 3
Base delay for non-throttling errors 50 ms
Base delay for throttling errors 1000 ms
Maximum delay 20 seconds
Token bucket size 500
Token cost per non-throttling retry 14
Token cost per throttling retry 5
Tokens added when an operation succeeds without retrying 1
Note

DynamoDB and DynamoDB Streams clients use a maximum of 4 attempts and a base delay of 25 ms for non-throttling errors.

Configuring retries

The standard retry mode is the only retry mode that this SDK currently supports. Setting retry_mode explicitly to anything other than standard raises a validation error during resolution. Because environment variables and shared config files are frequently shared across tools and SDKs, a legacy or adaptive value picked up from those sources is not treated as an error. It is mapped to standard and a warning is emitted, so a config file written for another SDK does not break your client.

The two settings that control retry behavior are the retry mode and the maximum number of attempts. If you set neither, resolving a configuration fills both in for you:

config = await AsyncBedrockRuntimeConfig.resolve() print(config.retry_mode) # "standard" print(config.max_attempts) # None
Note

max_attempts resolves to None when not explicitly set. This means the retry strategy uses its own built-in default (typically 3 for the standard strategy). It does not mean retries are disabled.

Values are resolved in order of precedence. An explicit argument to resolve() wins, then the environment variable, then the shared config file, and finally the built-in default. Precedence is evaluated per setting rather than per source, so max_attempts can come from your config file while retry_mode comes from the environment.

Both can be set in the environment:

export AWS_RETRY_MODE=standard export AWS_MAX_ATTEMPTS=5

Or in the shared config file:

# ~/.aws/config [default] retry_mode = standard max_attempts = 5

Or in code, when resolving a client configuration:

config = await AsyncBedrockRuntimeConfig.resolve( retry_mode="standard", max_attempts=5, ) async with AsyncBedrockRuntimeClient(config=config) as client: response = await client.some_operation(input)

max_attempts counts total attempts, not retries, so setting it to 1 disables retries entirely while still making the original request:

config = await AsyncBedrockRuntimeConfig.resolve(max_attempts=1)

If you need behavior the built-in strategy does not provide, you can supply a retry strategy of your own. A strategy passed this way takes precedence, and any retry_mode or max_attempts set outside of it is not consulted.

from smithy_core.aio.retries import SimpleRetryStrategy config = await AsyncBedrockRuntimeConfig.resolve( retry_strategy=SimpleRetryStrategy(max_attempts=10), ) print(config.retry_strategy.max_attempts) # 10

You can also implement your own retry strategy if the built-in options do not meet your needs. A custom strategy must satisfy the RetryStrategy protocol (smithy_core.aio.interfaces.retries.RetryStrategy), which requires a backoff_strategy attribute, a max_attempts attribute, and three async methods: acquire_initial_retry_token, refresh_retry_token_for_retry, and record_success. Any class that implements these is accepted by the SDK.