Skip to main content
429Retryable

OpenAI 429 Rate Limited

RPM/TPM exhausted for the model and tier — or, distinctly, `insufficient_quota` means your prepaid balance is empty (no retry will fix that).

Most likely causes

  1. 1.TPM limit hit by long contexts even at low request rates
  2. 2.insufficient_quota: billing balance/budget exhausted (not a rate issue)
  3. 3.Burst concurrency past RPM
  4. 4.Shared key used by multiple services without coordination

Fix checklist

  • Check error.code: insufficient_quota → add credits; rate_limit_exceeded → back off
  • Honor retry-after and x-ratelimit-* response headers
  • Spread load: client-side queue with token budgeting
  • Raise usage tier (limits scale with paid usage history)

Retry guidance

For rate_limit_exceeded: exponential backoff with jitter from 1s, honor retry-after. For insufficient_quota: do NOT retry — add credits.

// Retry 429 with exponential backoff + full jitter.
async function callWithBackoff(payload: unknown, maxAttempts = 5) {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const res = await fetch("https://api.openai.com/v1/chat/completions", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      },
      body: JSON.stringify(payload),
    });
    if (res.status !== 429) return res;
    // Honor Retry-After when present; otherwise exponential backoff, capped at 32s.
    const retryAfter = Number(res.headers.get("retry-after"));
    const base = Number.isFinite(retryAfter) && retryAfter > 0
      ? retryAfter * 1000
      : Math.min(1000 * 2 ** attempt, 32_000);
    await new Promise((r) => setTimeout(r, base * (0.5 + Math.random() * 0.5)));
  }
  throw new Error("OpenAI 429: still failing after backoff — check https://status.openai.com");
}

Provider status page: status.openai.com