In this categoryTroubleshooting ยท 27
- How to Fix an OpenAI 401 'Invalid API Key' ErrorStart
- How to Fix OpenAI 429 Rate Limit Errors With Backoff
- How to Fix Anthropic Claude API 401 Authentication Errors
- How to Fix Google Gemini 'API Key Not Valid' Errors
- How to Fix an API Key That Loads as Undefined
- How to Handle Anthropic 529 'Overloaded' Errors
- How to Fix Rate Limit Errors from an AI API
- How to Fix CORS Errors When Calling an AI API From the Browser
- How to Fix 'Model Not Found' and Deprecated Model Errors
- How to Rotate a Leaked API Key Without Downtime
- How to Fix SSL Certificate Errors When Calling AI APIs
- How to count tokens before sending a prompt to Claude
- How to Fix 'Context Length Exceeded' Token Limit Errors
- How to fix a context length exceeded error in the Claude API
- How to fix a Claude response that gets cut off mid-sentence
- How to reduce Claude hallucinations by grounding answers in your documents
- How to keep a long Claude conversation under the context limit
- How to stop Claude from calling tools when it should not
- How to handle a Claude Fable 5 refusal with a fallback model
- How to choose the right Claude model for cost and quality
- How to cut Claude API costs with prompt caching
- How to halve Claude costs for bulk jobs with the Batch API
- How to cap spend on a Claude agent with a task budget
- How to Debug an MCP Server That Will Not Connect
- How to Ask an Agent to Explain a Bug Before Fixing It
- How to Roll Back a Bad Deploy Quickly
- How to Fix Cursor Not Indexing Your Codebase
How to Fix OpenAI 429 Rate Limit Errors With Backoff
Stop your app from crashing on 429s by adding exponential backoff and reading the retry headers.
A 429 means you sent requests faster than your tier allows, or you ran out of tokens-per-minute headroom. The wrong reaction is to retry instantly in a tight loop, which makes it worse. The right fix is to back off, respect the retry hint the API gives you, and spread requests over time.
- A working OpenAI API key
- Node 18+ or Python 3.9+
- The ability to read response headers from your HTTP client
Step 1: Tell apart the two kinds of 429
There are two distinct causes. A rate limit means too many requests or tokens in a short window, and it clears on its own. An insufficient_quota error also returns 429 but means your account is out of credits, and no amount of retrying helps. Read the code field to know which one you have.
Step 2: Read the retry-after and ratelimit headers
The API ships headers that tell you exactly how long to wait and how much budget remains. Honor retry-after when present instead of guessing a delay.
Step 3: Add exponential backoff with jitter
Wrap your call in a retry loop that doubles the delay each attempt and adds a small random jitter so many clients do not retry in lockstep. Cap the number of attempts so a real outage does not hang forever.
async function withBackoff(fn, max = 5) {
for (let attempt = 0; attempt < max; attempt++) {
try {
return await fn();
} catch (err) {
if (err.status !== 429 || attempt === max - 1) throw err;
const retryAfter = Number(err.headers?.["retry-after"]) || 0;
const wait = retryAfter * 1000 || (2 ** attempt) * 500 + Math.random() * 250;
await new Promise((r) => setTimeout(r, wait));
}
}
}Step 4: Lower your request pressure
Backoff treats the symptom. To stop hitting the limit at all, batch where you can, use a smaller model for cheap calls, and add a concurrency limit so you never have more than a handful of in-flight requests at once.
Result
With backoff plus a concurrency cap of 5, a batch job that previously failed on roughly one in ten calls now finishes cleanly. The job is a little slower during peak windows but never drops a request.
Watch related tutorials
12:38
14:09
17:53
15:00
12:00
1:42:18New guides in your inbox
Fresh step-by-step how-to guides as we publish them. One email a week, no more.