Errors and throttling¶
Exceptions¶
Everything the library raises derives from AmazonAdsError.
| Exception | When |
|---|---|
ConfigurationError |
Missing credentials, unknown or ambiguous market |
AuthError |
Login with Amazon refused a token (.error, e.g. invalid_grant) |
BadRequestError |
400 |
UnauthorizedError |
401 after a token refresh |
ForbiddenError |
403: no access to this profile or operation |
NotFoundError |
404 |
UnprocessableError |
422: valid request Amazon will not act on |
ThrottledError |
429 after every retry (.retry_after) |
ServerError |
5xx |
PartialFailureError |
Some batch items failed, from raise_for_errors() (.result) |
ReportFailedError |
A report failed or timed out (.report_id, .status) |
PlanDriftError |
A plan's before values no longer match the account (.drifted) |
UnsupportedOperationError |
call() was given a catalog operation this client cannot send, such as an mcp-* tool of Amazon's hosted MCP server. Raised before any request. |
Every ApiError carries status_code, Amazon's code, the message, the parsed body,
the method and url, and request_id (Amazon support asks for this).
from amazon_ads import ApiError
try:
us.sp.keywords.list()
except ApiError as exc:
print(exc.status_code, exc.code, exc, exc.request_id)
Retries¶
| Response | Retried? | Wait |
|---|---|---|
| 429 Too Many Requests | Always: Amazon rejected it unprocessed | Retry-After if sent, else exponential backoff with jitter |
| 500, 502, 503, 504 | Only requests safe to repeat (reads, lists, report polling) | Exponential backoff with jitter |
| Timeout after sending | Only requests safe to repeat | Exponential backoff with jitter |
| Connection refused (nothing sent) | Always | Exponential backoff with jitter |
| 401 | Once, after refreshing the token | None |
A write that fails with 5xx or times out may still have been applied, and resending a create could duplicate campaigns or keywords. So writes raise instead of retrying: check the account (list the entities) before trying again.
The same rules apply to single items inside a 207 batch response. An item Amazon marks
throttledError is sent again on its own with backoff. An item marked
internalServerError is sent again for updates and archives, but not for creates. Every
other per-item error comes back in the BatchResult with its hint and any allowed range
(see batch results).
A 429 also starts a shared cooldown. Every other request through the same client waits it out too, instead of making things worse.
Tune it:
from amazon_ads import AmazonAds, RetryPolicy
ads = AmazonAds.from_env(retry=RetryPolicy(max_attempts=10, backoff_max=120, max_total_wait=900))
Logging¶
The library logs to the amazon_ads logger: throttling waits at INFO, retries at
WARNING, every request with its status and Amazon request id at DEBUG.
import logging
logging.basicConfig()
logging.getLogger("amazon_ads").setLevel(logging.DEBUG)