Retries and backoff
Retry these
Do not retry these unchanged
Retrying any of those repeats a request that is wrong, at cost, until a quota stops
you. IDEMPOTENCY_KEY_REUSED is the one most likely to be retried by accident: it
looks like a conflict that might clear, and it never will, because the conflict is
between two things you sent.
Every error response also says so itself: error.retryable is true exactly for
the codes above that may be retried, and error.doc_url links the code’s row in the
error reference. Both are fields of the JSON error envelope,
so they work over plain HTTP today.
The SDKs expose them on ApiError as retryable and doc_url (Python) or docUrl
(TypeScript).
Keep the idempotency key across retries
The retried call must carry the same Idempotency-Key as the attempt that
failed. A retry with a fresh key is a second submission, and it will be analysed and
billed. See Idempotency.
Honour Retry-After, then back off
When Retry-After is present, use it. It is not a suggestion — it is the server
telling you when it will be able to answer, and ignoring it converts a brief
saturation into a sustained one.
A 429 can also carry RateLimit-* headers naming each limit and when it resets; see
Rate limits.
When it is absent, use capped exponential backoff with jitter:
The jitter matters more than the exponent. Without it, every client that failed at the same moment retries at the same moment, and the retry storm is the outage.
Two deadlines, not one
A per-request timeout alone gives you an unbounded loop of individually quick calls. An overall deadline alone lets one hung socket consume the whole budget. You want both, and you want the overall deadline to be shorter than whatever is waiting on you upstream.
When the overall deadline expires, stop waiting — but remember that stopping does not cancel the job. Persist the job id, return control, and pick the result up later. The analysis will finish.
Polling retries keep the ETag
A retried poll should still send If-None-Match with the last ETag you held. A
304 is cheaper for both sides, and the retry does not invalidate what you cached.