2 min read
Decide first
| Status | Retry? | Why |
|---|---|---|
429 | Yes, after Retry-After | Transient — the window resets |
500/502/503/504 | Yes, with backoff | Transient server-side |
400/404/409/422 | No | Deterministic — will fail again |
401/403 | No | Fix the credential first |
Backoff with jitter
async function withRetry(fn, max = 5) {
for (let attempt = 0; ; attempt++) {
const res = await fn();
if (res.status < 400) return res;
const retryable = res.status === 429 || res.status >= 500;
if (!retryable || attempt >= max) return res;
const ra = Number(res.headers.get('Retry-After')) || 0;
const backoff = Math.min(2 ** attempt, 32);
const jitter = Math.random() * backoff;
await sleep(1000 * Math.max(ra, backoff / 2 + jitter));
}
}
Retries and idempotency
A retry after a timeout is dangerous for writes: the first request may have succeeded before the connection dropped. Send an idempotency key so the server recognises the replay and returns the original result instead of creating a duplicate. See Retry a write safely.
Frequently asked questions
How many times should I retry?
Cap it — 3 to 5 attempts is plenty for transient errors. Beyond that you are usually queuing work that needs a human, not waiting out a blip. Always add jitter so a fleet of clients does not retry in lockstep.
Do I need Retry-After if I already back off?
On a 429, honour Retry-After — it is the server telling you exactly when the window resets, which is more accurate than your own backoff. Fall back to backoff only if the header is absent.
Is it safe to retry a POST?
Only with an idempotency key. Without one, a retried POST after a silent success creates a duplicate. See Retry a write safely.
Funding for UK limited companies
Credicorp lends to your company, not to you personally — short-term working capital with no personal guarantee. See what your business could access.