Skip to content

Retry-After in HTTP-date form produces a NaN backoff delay #98

Description

@KalebCole

src/lib/http.ts:59-95:

const retryAfter = resp.headers?.get('retry-after');
const delay = retryAfter ? Math.min(30, parseFloat(retryAfter)) * 1000
                         : Math.min(30000, (2 ** attempt + Math.random()) * 1000);

RFC 9110 §10.2.3 permits Retry-After in two forms:

  • delta-seconds — e.g. Retry-After: 120
  • HTTP-date — e.g. Retry-After: Wed, 21 Oct 2026 07:28:00 GMT

On the date form, parseFloat returns NaN. Math.min(30, NaN) is NaN, so delay is NaN ms and the backoff is undefined behavior — setTimeout(r, NaN) coerces to 0, meaning the client retries immediately and hammers a server that explicitly asked it to wait.

This fires precisely on 429s, where the header is most likely to be present and most likely to matter.

Fix

  • Detect the two forms: if parseFloat yields NaN, try Date.parse and compute the delta from now.
  • If both fail, fall back to the exponential-backoff branch rather than propagating NaN.
  • Clamp the result to the existing 30s ceiling and guard against negative deltas (a past date).
  • Unit-test both header shapes plus the malformed case.

Related

Same failure family as the missing request timeout — the retry layer degrades under exactly the adverse conditions it exists to handle.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions