Reference guide · http-status · Published 2026-08-16 · 3 min read
Retry-After header explained
Retry-After header explained: delta-seconds vs date form, how 429 and 503 use it, and how clients retry without hammering the server.
- ·Two valid forms
- ·Statuses that use it
- ·Clients that honor it
Retry-After is the HTTP header a server uses to tell a client when it can come back: either a number of seconds, or an absolute HTTP-date. It appears almost always with a throttling or temporary status (429, 503), so it is the part of the contract that turns "wait" from a guess into a promise.
Two valid forms
The header has exactly two legal shapes:
Retry-After: 120
Retry-After: Wed, 21 Oct 2026 07:28:00 GMT
- Seconds form: seconds to wait. Use it when the server knows the interval, e.g. after a cooldown tripped 30 seconds ago.
- Date form: the absolute moment to retry. Useful when the server restarts at a scheduled time and the client can see the wall clock exactly.
Clients must treat any other value as garbage: a server that sends Retry-After: "2 minutes" or Retry-After: never has to get a sane fallback, and a well-built client falls back to its own exponential backoff instead of crashing.
What uses it
| Status | Typical message | What the header says |
|---|---|---|
| 429 | Too many requests | Wait the window before the bucket refills |
| 503 | Service unavailable | Wait until the drain is done / the restart lands |
| 301/302 (rare) | Redirect reply | A delay hint before fetching the new location |
How clients should honor it
A correct client does three things:
- Parse and clamp. Read the value; if it is a date, compute the delta from now. Never retry instantly, and never sleep for a giant value like
86400if the job cannot wait; the caller decides. - Retry the same request. Retry with the same method and body, honoring the header before sending the next attempt. A 429 to a
POSTmust not become aGETto the same URL. - Fall back when absent. If the response has no
Retry-After, use the status-family default: exponential backoff with jitter (start around 1s, double on each retry, cap at the deadline).
import time
def wait_after(response):
value = response.headers.get("retry-after")
if value is None:
return min(2 ** attempt, 60) # exponential backoff, capped
try:
return float(value)
except ValueError:
return 60 # unparseable: fall back to a sane cap
The two sides of the same coin
- A server sends
Retry-After: 30, and a client that ignores it re-fires instantly and stays locked out forever. The header is the fastest way to heal a burst because the client stops hammering. - A server that omits the header leaves clients guessing and the site under extra load during the exact window it is weakest. A
503with noRetry-Afteris the classic cold-restart problem, where traffic returns all at once.
Verify a stack honors it
Test your throttling path end to end:
for i in 1 2 3 4 5; do
curl -s -o /dev/null -w "%{http_code} %header{retry-after}\n" https://example.com/api/check
sleep 1
done
Read the printed status and header pairs, then compare the time between the 429 and the 200 with the Retry-After value. If the client returns at exactly the promised value, the pair works.
When to involve a professional
If third-party clients consistently report "locked out" on a 429/503 while your own tests pass, the client is ignoring the header or your proxy is stripping it. Ask the vendor or check the edge: many CDNs drop response headers, and a Retry-After that never reaches the client can be restored at the edge layer.