OpenAI API 429 and Timeout Errors in Production: Fix Guide

OpenAI 429 'rate limit' vs 'insufficient_quota', slow responses, and timeouts. How to tell them apart and build retries, queues, and fallbacks that keep your AI feature up.

An OpenAI API 429 can mean two different things: a rate limit you can retry after waiting, or insufficient_quota which no retry will fix; read the error code in the response body, retry only the first with exponential backoff and jitter, and add timeouts and a fallback for slow responses.

AI features fail differently from normal APIs: calls are slow, usage is bursty, and quota is a billing issue as much as an engineering one.

Tell the Two 429s Apart

Both return HTTP 429. The body differs:

error.code (or type) Meaning Action
rate_limit_exceeded Too many requests or tokens per minute Back off and retry, reduce concurrency
insufficient_quota Out of credit or hit a billing cap Do not retry; alert a human, fix billing

Treating insufficient_quota as retryable creates a retry storm that fails every time and delays the real fix. Log the code on every error.

Fix 1: Retry With Backoff and Jitter

The official SDKs already retry some errors, with a default of 2 retries. Tune it and set a timeout:

import OpenAI from 'openai'

const client = new OpenAI({
  maxRetries: 3,
  timeout: 30_000, // ms. The SDK default is much longer, which can outlive your function limit
})

For custom logic, honor the retry-after header when present:

async function callWithBackoff<T>(fn: () => Promise<T>, tries = 4): Promise<T> {
  for (let i = 0; i < tries; i++) {
    try {
      return await fn()
    } catch (e: any) {
      const retryable = e?.status === 429 && e?.code !== 'insufficient_quota'
      if (!retryable || i === tries - 1) throw e
      const wait = Number(e?.headers?.['retry-after']) * 1000 || 500 * 2 ** i
      await new Promise(r => setTimeout(r, wait + Math.random() * 250))
    }
  }
  throw new Error('unreachable')
}

More on retry design, budgets, and what is safe to retry in API Timeout Errors in Node.js.

Fix 2: Respect Your Own Function Timeout

LLM calls can take many seconds. If your serverless function limit is shorter than the SDK timeout, the platform kills you first with a 504. Set the client timeout below your function's maxDuration and stream the response so the user sees output sooner. See Vercel function timeouts.

Fix 3: Smooth Out Bursts With a Queue

Rate limits are per minute. A burst of 200 users hitting at once exceeds it even if average load is fine. Put non-interactive work (summaries, batch jobs) in a queue with a concurrency limit and let it drain. Monitor the worker as described in BullMQ failed jobs monitoring.

Fix 4: Cache and Reduce Tokens

  • Cache identical prompts (hash the prompt and parameters) in Redis for deterministic tasks; see Redis Upstash on serverless.
  • Trim system prompts and context, since tokens per minute is often the real limit.
  • Use a smaller model for easy tasks.

Fix 5: Degrade Gracefully

Decide what the feature does when the model is unavailable: show a cached answer, a simpler rule-based fallback, or a clear message with a retry button. A spinner that never ends is the worst outcome.

Log What You Need to Debug

Record the model, token counts, latency, status, error.code, and the x-request-id response header. That ID lets OpenAI support trace a specific failed call.

Validate the Output Too

Model output is untrusted input. If you expect JSON, parse and validate it with a schema; see Zod validation errors. Failed parses are production errors, not edge cases.

Let Relia Watch the AI Path

Relia watches your AI-agent runs and the production paths around your AI calls. When failures pile up, it writes the incident up in plain words: what happened, why it thinks so (with a confidence level), and one thing to do next. On request it writes a fix plan, such as adding backoff, timeouts, or fallback handling, with a "Copy for your AI assistant" button; Relia doesn't change code itself.

FAQ

Why do I get 429 when I am under my rate limit?

Limits apply to both requests and tokens per minute, and bursts count. A short spike can exceed the limit even when your average does not.

What does insufficient_quota mean? Your account has no remaining credit or hit a spend limit. Retries will not help; fix billing.

What timeout should I set for LLM calls?

Shorter than your platform's function limit, typically 20-60 seconds, with streaming for long outputs.

All guides