OpenAI API errors look scary, but most of them have a simple cause and a quick fix. A 401 is almost always the key, and a 429 is either speed or money.
This guide explains every common status code, shows the newer error codes OpenAI added recently, and gives you copy-paste Python retry code that handles them the right way.
- 401: wrong, deleted or mistyped API key, wrong organization, or an IP not on your allowlist.
- 403: you are calling from an unsupported country or region, or the key lacks access.
- 404: the model id or resource does not exist for your project. Check the exact id, such as
gpt-6.1-sol. - 429 has two meanings: a rate limit (retry later) or a quota or billing limit (retrying never helps). Check
error.code. - 500 and 503: trouble on OpenAI’s side. Retry with backoff and check the status page.
- The SDK retries for you: 2 retries by default, with a 10 minute timeout. Tune
max_retriesandtimeout.
OpenAI API Error Cheat Sheet
The official Python SDK (version 3.49.0 at the time of writing) turns each HTTP status into its own exception class. Here is the quick map, based on the SDK README and OpenAI’s error code guide.
| Status | Python exception | Usual cause | Retry? |
|---|---|---|---|
| 400 | BadRequestError |
Bad parameters, too much input, invalid service_tier |
No, fix the request |
| 401 | AuthenticationError |
Bad key, wrong org, IP not allowed | No |
| 403 | PermissionDeniedError |
Unsupported region or no access | No |
| 404 | NotFoundError |
Wrong model id or resource id | No |
| 409 | ConflictError |
Resource changed by another request | Yes |
| 422 | UnprocessableEntityError |
Valid request that could not be processed | Yes |
| 429 | RateLimitError |
Rate limit, slow down, or quota and spend limits | Only for rate limits |
| 500+ | InternalServerError |
Server error or overloaded model (503) | Yes, with backoff |
| None | APIConnectionError / APITimeoutError |
Network, proxy, SSL or timeout | Yes |
Every error inherits from openai.APIError. Status errors also inherit from openai.APIStatusError, which gives you status_code and the raw response.
401 Errors: Authentication Problems
OpenAI lists four different 401 messages. Each points to a different fix.
- Invalid Authentication: the key was revoked, belongs to another organization or project, or lacks permission for that endpoint.
- Incorrect API key provided: a typo, an extra space, a deleted key, or an old key cached in your environment.
- You must be a member of an organization: you were removed from the org, left it, or the org was deleted.
- IP not authorized: your server’s IP is not on the project or org IP allowlist.
How to fix a 401
- Print the key prefix only. Check that your code loads the key you expect. Never print the full key.
- Look for spaces and quotes. A trailing newline from a
.envfile is a common cause. - Check the project. Project keys only work for that project. Make sure the key and the org match.
- Restart your shell or server. Old values of
OPENAI_API_KEYcan stay in memory. - Create a new key. If nothing else works, generate a fresh key in the dashboard and delete the old one.
import os
key = os.environ.get("OPENAI_API_KEY", "")
print("Key loaded:", bool(key), "prefix:", key[:7], "length:", len(key))
Warning: Never paste your full key into logs, chat tools or screenshots. If a key leaks, delete it right away and make a new one.
403 Errors: Permission and Region
The documented 403 is “Country, region, or territory not supported”. It means the request comes from a place where OpenAI does not offer the API.
This often happens when code runs on a cloud server in a different country from you. Check where your server or VPN exit really is, then compare it with OpenAI’s supported countries page.
A PermissionDeniedError can also mean your key cannot reach a specific resource, such as a file or fine-tune in another project. Check the key, the org id and the resource id together.
404 Errors: Model Not Found
A 404 raises NotFoundError. With models, it usually means the id is wrong, retired, or not open to your project.
The current GPT-6 family ids on OpenAI’s models page are:
- gpt-6-astra: flagship for complex reasoning and coding.
- gpt-6.1-sol: balance of intelligence and cost.
- gpt-6.1-terra: fast and efficient.
- gpt-6-luna: smallest, for high-volume tasks.
Copy the id exactly, including dots and dashes. Some special models, such as the cyber models, are limited to approved users, so a normal key may not see them. Prices for each model are in my OpenAI API pricing guide.
Tip: Call client.models.list() to see exactly which model ids your key can use. If a model is missing there, no amount of retrying will fix the 404.
429: Rate Limit vs Quota
This is the error people get wrong most. A 429 can mean “slow down” or it can mean “you are out of money”. The fix is completely different, so read error.code.
| Code or message | What it means | Fix |
|---|---|---|
| Rate limit reached for requests | Too many requests or tokens per minute | Wait, honour Retry-After, back off |
slow_down |
Your traffic ramped up too fast, even inside your limits | Cut traffic, then ramp up slowly |
credit_balance_exhausted |
Prepaid credits are used up | Add credits in billing |
project_spend_limit_exceeded |
The project hit its monthly spend limit | Raise the project limit or wait for reset |
organization_spend_limit_exceeded |
The whole org hit its monthly spend limit | Raise the org limit or wait for reset |
organization_usage_limit_exceeded |
The org hit its OpenAI-assigned monthly usage limit | Request a higher limit or contact support |
OpenAI notes that the broader error.type can still say insufficient_quota for billing errors. That is why you should check the specific code. Retrying a quota error never restores access.
Usage tiers and limits
Your limits grow with your total credit purchases. OpenAI’s rate limit guide lists these tiers:
- Free: no purchase needed in allowed regions, with a $100 monthly usage limit.
- Build: after $5 in purchases, $500 monthly limit.
- Launch: after $100, $5,000 monthly limit.
- Grow: after $500, $200,000 monthly limit.
Limits are measured as requests and tokens per minute and per day. They are shared across your whole organization, so another app on the same org can use up your budget. My LLM API rate limits guide compares tiers across providers.
Note: OpenAI counts the larger of your max_tokens and the estimated size of your input toward the token limit. Setting a huge max_tokens you never use can trigger 429s early.
Handling slow_down
The slow_down code is fairly new. OpenAI’s rule of thumb is that above 1M input tokens per minute, you should raise traffic by no more than 50% every 15 minutes.
500 and 503 Server Errors
- 500 “The server had an error while processing your request”: a problem on OpenAI’s side. Wait briefly, retry, and check the status page.
- 503 “Model temporarily overloaded”: the code is
server_is_overloaded. The model is short on capacity. HonourRetry-Afterand lengthen the wait if it repeats.
Here is a catch. In Python, a 503 raises InternalServerError, not RateLimitError. OpenAI’s docs warn that handlers which only catch RateLimitError for throttling will miss overload errors.
OpenAI also changed codes recently. Overload used to return 503 with slow_down. Now fast ramps return 429 slow_down and overload returns 503 server_is_overloaded. Update any code that matched the old pattern.
Timeouts and Connection Errors
If the SDK cannot reach OpenAI at all, it raises APIConnectionError. If the request takes too long, it raises APITimeoutError.
- Default timeout: 10 minutes per request.
- Default retries: 2, with a short exponential backoff.
- What gets retried: connection errors, 408, 409, 429 and 500+ errors.
- Not retried: streams that already started, because replaying could duplicate output.
from openai import OpenAI
client = OpenAI(
timeout=30.0, # seconds, default is 10 minutes
max_retries=3, # default is 2
)
# Override for one slow call
resp = client.with_options(timeout=120.0).responses.create(
model="gpt-6.1-sol",
input="Summarise this long report...",
)
Connection errors often come from proxies, firewalls or SSL inspection on company networks. Since version 3.0, the SDK uses httpx2 under the hood, so check your proxy settings work with it.
Context Length Errors
If your input plus the requested output is larger than the model’s window, the API returns a 400 BadRequestError. The message explains that the request is longer than the model allows.
The GPT-6 family models have a 1.05M token context window and up to 128K output tokens. That is large, but long chat histories, big files and tool results can still fill it.
- Trim history: keep only the last few turns, or summarise older ones.
- Chunk documents: split big files and process them in parts.
- Lower max output: reduce
max_output_tokensto what you really need. - Count tokens first: estimate size before sending so you fail fast in your own code.
Retry Code That Does It Right
The SDK’s built-in retries are fine for small scripts. For production, many teams turn them off and use their own loop. That way they can honour Retry-After, skip quota errors, and log request ids.
import random
import time
import openai
from openai import OpenAI
client = OpenAI(max_retries=0) # we handle retries ourselves
NO_RETRY_CODES = {
"insufficient_quota",
"credit_balance_exhausted",
"project_spend_limit_exceeded",
"organization_spend_limit_exceeded",
"organization_usage_limit_exceeded",
}
def call_with_retry(max_attempts=6, base=1.0, cap=60.0, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return client.responses.create(**kwargs)
except (openai.RateLimitError, openai.InternalServerError) as e:
if getattr(e, "code", None) in NO_RETRY_CODES:
raise # billing problem, retrying will not help
wait = None
retry_after = e.response.headers.get("retry-after") if e.response else None
if retry_after:
try:
wait = float(retry_after)
except ValueError:
wait = None
if wait is None:
wait = min(cap, base * 2 ** (attempt - 1))
wait += random.uniform(0, 1) # jitter
req_id = e.response.headers.get("x-request-id") if e.response else None
print(f"{e.status_code} {e.code} attempt {attempt}, waiting {wait:.1f}s, request {req_id}")
if attempt == max_attempts:
raise
time.sleep(wait)
except (openai.APIConnectionError, openai.APITimeoutError):
if attempt == max_attempts:
raise
time.sleep(min(cap, base * 2 ** (attempt - 1)) + random.uniform(0, 1))
resp = call_with_retry(model="gpt-6.1-sol", input="Say hello in one word.")
print(resp.output_text)
This loop follows OpenAI’s own advice: use Retry-After as the minimum wait, add jitter, cap the attempts, and never retry billing errors. Note that APITimeoutError is a subclass of APIConnectionError, so one handler covers both.
Warning: Do not stack your own retries on top of SDK retries. With the default of 2 SDK retries inside a 6-attempt loop, one failing call can turn into 18 requests and make a rate limit worse.
How to Prevent Errors in Production
- Watch the headers: read
x-ratelimit-remaining-requestsandx-ratelimit-remaining-tokensand slow down before you hit zero. - Log request ids: every response has
_request_id. For errors, read thex-request-idheader. Support needs it. - Set spend alerts: project and org spend limits stop surprise bills, but they also cause 429s. Set alerts below the limit.
- Use Batch for bulk jobs: the Batch API has its own queue limits and keeps big jobs out of your live traffic.
- Ramp slowly: when launching, grow traffic in steps to avoid
slow_down. - Add a fallback model: if a big model returns 503, a smaller one such as
gpt-6.1-terracan keep your app running.
Getting started with the SDK? See my OpenAI API Python tutorial. If the ChatGPT app is failing rather than the API, my ChatGPT not working guide is the better fit.
Troubleshooting Checklist: Common Problems and Fixes
- Read the status and the code: print
e.status_code,e.codeande.message. The code tells you more than the number. - Check the key: loaded, no spaces, right project, not deleted.
- Check billing: credits left, and no project or org spend limit reached.
- Check the model id: run
client.models.list()and copy the id exactly. - Check the region: is your server in a supported country?
- Check the status page: for 500 and 503 errors, see whether OpenAI has an incident.
- Check your retries: are SDK retries and your own retries stacking?
- Check the input size: for 400 errors, trim history or lower max output tokens.
Using other providers too? Compare with my Claude API errors guide and Gemini API errors guide.
Frequently Asked Questions
Why do I get 429 when I have barely used the API?
Check error.code. If it says a quota, credit or spend limit, you need to add credits or raise a limit. If it is a rate limit, another app on your organization may be sharing the same limits.
What is the difference between insufficient_quota and a rate limit?
A rate limit is temporary and clears after a short wait. A quota or billing error stays until you add credits or raise your spend limit, so retrying does nothing.
Does the OpenAI Python SDK retry automatically?
Yes. It retries connection errors, 408, 409, 429 and 500+ errors 2 times by default. Change it with max_retries, or set it to 0 to turn retries off.
What is the default timeout in the OpenAI SDK?
Ten minutes per request. Set a shorter timeout on the client or per call with with_options.
Why does a 503 not raise RateLimitError?
The SDK maps all 500+ codes, including 503, to InternalServerError. Catch both RateLimitError and InternalServerError in your retry logic.
How do I fix “Incorrect API key provided”?
Check for typos and extra spaces, make sure the key is from the right project, and restart your app so it loads the new value. If it still fails, create a new key.
What does the slow_down error mean?
Your traffic grew too fast, even if you are under your per-minute limits. Reduce the rate, honour Retry-After, and ramp up gradually.




