The Retry-After header: what it means on 429, 503, 413 and 3xx, and how clients should read it

Retry-After per RFC 9110 and RFC 6585: its two value formats, what it means with each status code, turning an HTTP-date or a seconds value into a wait, and handling invalid or huge values.

DevelopmentWebNetworking

Retry-After is the response header a server uses to say how long the client should wait before its next request. It is defined in section 10.2.3 of RFC 9110, the HTTP Semantics specification, and its meaning shifts a little depending on the status code it arrives with. The value can also take two forms, so a client has to be able to read both.

Two value formats

Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
Retry-After: 120

The grammar is Retry-After = HTTP-date / delay-seconds. The first line means “wait until that moment”. The second means “wait 120 seconds”, which is 2 minutes, after receiving the response.

delay-seconds is 1*DIGIT: a non-negative decimal integer. So 1.5, -1, +30 and 2m don’t match the grammar. The clock starts when the response is received, not when the request was sent.

HTTP-date is the date format from section 5.6.7. A sender MUST generate it as IMF-fixdate (Sun, 06 Nov 1994 08:49:37 GMT), but a recipient MUST accept all three formats, including two obsolete ones.

Format Example
IMF-fixdate (preferred) Sun, 06 Nov 1994 08:49:37 GMT
RFC 850 format (obsolete) Sunday, 06-Nov-94 08:49:37 GMT
asctime format (obsolete) Sun Nov 6 08:49:37 1994

All three are UTC. The asctime format carries no zone, but it is assumed to be UTC. HTTP-date is case-sensitive. For the RFC 850 format, which has a two-digit year, a recipient MUST read a date that appears to be more than 50 years in the future as the most recent past year with the same last two digits. Leading and trailing whitespace is not part of a field value, so a parser MUST strip it before evaluating the value (section 5.5).

What it means with each status code

Status Source What Retry-After indicates Requirement
503 Service Unavailable RFC 9110 10.2.3, 15.6.4 How long the service is expected to be unavailable MAY send
3xx redirects RFC 9110 10.2.3 The minimum time the client is asked to wait before issuing the redirected request None stated
413 Content Too Large RFC 9110 15.5.14 That the condition is temporary, and after what time the client may try again SHOULD send if temporary
429 Too Many Requests RFC 6585 section 4 How long to wait before making a new request MAY send

Some of this doesn’t fit in a table.

503. The spec defines 503 as the server being unable to handle the request right now because of temporary overload or scheduled maintenance. It also notes that an overloaded server doesn’t have to use 503; some simply refuse the connection. A 503 without Retry-After doesn’t mean recovery is imminent.

3xx. Section 10.2.3 defines Retry-After on any 3xx response as the minimum time the user agent is asked to wait before issuing the redirected request. So it isn’t “send it after this time”; it is a minimum wait the client is asked to observe. Not every 3xx has a Location to follow, though. Section 15.4 separates redirects that point to another URI through Location (301, 302, 303, 307, 308) from 300, which offers a choice, and 304, which points the client to a stored result. When a response does carry Location and the client sends the redirected request to that target, the minimum wait applies to that request. The differences between the redirect codes themselves are covered in 301, 302, 307 and 308 redirects.

413. This means the request content was too large to process. The spec says that if the condition is temporary, the server SHOULD send Retry-After to indicate that it is temporary and after what time the client may try again. So a 413 with Retry-After can be read as the server signalling a temporary condition. The reverse doesn’t hold: a 413 without Retry-After doesn’t establish that the limit is permanent. SHOULD is not MUST, and a server may send a bare 413 even when the condition is temporary. The header alone can’t tell the client whether the condition is temporary, so the decision to resend has to come from the rest of the response or from the application’s own policy.

429. RFC 6585 says a 429 response SHOULD include details explaining the condition and MAY include Retry-After. It does not define how the server identifies the user or counts requests. A server might count per resource, across the whole server, or across a set of servers. So the header alone doesn’t tell the client whether the wait covers one URL or the whole host. A 429 response MUST NOT be stored by a cache.

The definition in 10.2.3 isn’t tied to particular status codes. It gives a general meaning, how long the user agent ought to wait before a follow-up request, and then spells out what it means with 503 and with 3xx. In the IANA HTTP Field Name Registry, Retry-After has status permanent and points to RFC 9110 section 10.2.3.

Turning the value into a wait

The code below is an example built on the spec’s rules. The cap and the use of the Date header are this article’s suggestions, not something the spec requires. It is partial pseudocode and won’t run as is: a conforming HTTP-date parser is deliberately left out, and parseHttpDate only marks where one would go.

// Placeholder: an HTTP-date parser that handles IMF-fixdate, RFC 850
// and asctime goes here. This article doesn't implement it.
declare function parseHttpDate(value: string): number | null;

// Returns the wait in milliseconds, or null if the value can't be parsed.
function retryAfterMs(
  value: string,
  receivedAt: number,        // when the response arrived (ms, local clock)
  serverDate: number | null, // the same response's Date header (ms), or null
  maxMs: number,             // the cap this client chooses
): number | null {
  const v = value.trim();
  if (/^[0-9]+$/.test(v)) {
    return Math.min(Number(v) * 1000, maxMs);
  }
  const at = parseHttpDate(v); // placeholder (see above)
  if (at === null) return null;
  const base = serverDate ?? receivedAt;
  return Math.min(Math.max(at - base, 0), maxMs);
}

The decisions in that code:

  • Seconds count from when the response arrived. The spec says “after receiving the response”. Counting from when the request was sent makes the client retry early by the round-trip time.
  • A date is a time on the server’s clock. If the client’s clock is off, date - now is off by the same amount. So when the response also has a Date header, this example waits Retry-After time - Date. That is this article’s suggestion, not a procedure from the spec, and it is only a conservative fallback for avoiding clock skew. Under section 6.6.1 of RFC 9110, Date is when the message was originated, but the client starts waiting only after it receives the response. The calculation therefore over-waits by the time the response took to get from its origination to the client, and if an intermediary such as a cache served a stored response, it can over-wait by however long that response was stored as well. The same section says an origin server with a clock MUST send Date on 2xx, 3xx and 4xx responses but only MAY send it on 5xx. A 503 can arrive without Date; the example then falls back to the receipt time on the local clock and inherits the clock skew described above.
  • A date already in the past means zero. The spec has no rule for this. There’s simply no reason to wait longer.
  • Cap the value. 1*DIGIT has no length limit, so a huge number is grammatically valid. Converting it straight to an integer type can overflow, and one mistaken value could stall a client for days. The right cap depends on the service.
  • Treat an unparseable value as absent. Section 10.2.3 doesn’t say what to do with 1.5 or a malformed date. This example returns null and leaves the caller to apply its own backoff.

Waiting doesn’t make a retry safe

Retry-After says when to send again. It says nothing about whether resending that request is safe. Section 9.2.2 of RFC 9110 says a client SHOULD NOT automatically retry a request with a non-idempotent method unless it knows the request is actually idempotent or can tell that the original was never applied. A 503 or 429 with Retry-After doesn’t lift that rule. See safe and idempotent HTTP methods for the details.

The wording in 10.2.3 is also “ought to wait”, not a BCP 14 keyword like MUST. What the server sends is advice, and following it is up to the client. For 3xx the wording is a little firmer: it is the minimum time the user agent “is asked to” wait.

Sending it from a server

These are suggestions drawn from the spec’s rules.

  • If you send a date, it MUST be IMF-fixdate. The other formats exist only so recipients stay compatible.
  • A seconds value is unaffected by clock differences between server and client. When there is a fixed time, such as the end of a maintenance window, a date states the intent more directly.
  • If many clients get the same date, they may all come back at the same moment. The spec doesn’t address this, but it is worth considering slightly different values per client on the server, or a random delay added by the client.
  • A 429 SHOULD explain the limit in its body. Retry-After alone can’t tell the client what the limit applies to.

Sources

Links and content checked on 14 October 2026.

Back to the blog