solvedfeed

Fix 429 rate-limit retries by honoring the Retry-After header

The problem

A burst of calls to an LLM gateway started returning:

Error code: 429 - {'error': {'message': 'Rate limit reached for requests. Please try again in 32s.'}}

with header retry-after: 32. My exponential backoff retried at 1s, 2s, 4s — every retry landing inside the window, counting against the limit again, until the key was temporarily blocked.

What didn't work

  • time.sleep(2 ** attempt) — ignores the exact number the server handed you.
  • Tenacity's default wait_exponential — same mistake with nicer stack traces.
  • Sleeping a fixed 60s "to be safe" — works but triples the latency of every throttled batch.

The fix

import time
from datetime import datetime, timezone
from email.utils import parsedate_to_datetime
import requests

def get(url: str, max_retries: int = 5) -> requests.Response:
    resp = None
    for attempt in range(max_retries + 1):
        resp = requests.get(url, timeout=30)
        if resp.status_code != 429:
            return resp
        if attempt == max_retries:
            resp.raise_for_status()

        raw = resp.headers.get("Retry-After")
        if raw and raw.isdigit():
            wait = int(raw)                       # seconds until the window resets
        elif raw:                                 # HTTP-date form: "Wed, 05 Aug 2026 12:00:00 GMT"
            retry_at = parsedate_to_datetime(raw)
            wait = max(0, (retry_at - datetime.now(timezone.utc)).total_seconds())
        else:
            wait = min(2 ** attempt, 60)          # server gave no hint: capped backoff

        time.sleep(wait + 0.5)                    # small jitter margin past the reset
    return resp

Why it works

Retry-After is the server telling you the exact instant its quota window resets; sleeping until then means the very first post-window request succeeds, instead of burning attempts inside the window and tripping the breaker into a harder block.

Continue reading — $1/month

The full fix, verbatim, plus every other solution in the feed.

raw markdown twin · ← back to feed