A 500 from OpenAI is an internal failure and is retryable. A 503 comes in two documented flavours: The engine is currently overloaded, please try again later, which is capacity, and Slow Down, which is OpenAI asking you specifically to reduce your rate and hold it for fifteen minutes. Neither 502 nor 504 appears in OpenAI documentation at all, which usually means they came from a proxy, load balancer, or CDN in your own path rather than from OpenAI. The official SDKs already retry connection errors, 408, 409, 429, and anything 500 or above twice by default, honouring Retry-After. The real hazard for agent workloads is not the retry itself but the tool call that already executed before the error arrived.
- OpenAI documents 500 and two different 503s. It documents neither 502 nor 504.
- A 502 or 504 is usually yours: a proxy, a load balancer, or a CDN between you and the API.
Slow Downis not generic overload. It is a specific instruction: reduce your rate and hold it 15 minutes.- SDKs retry twice by default on connection errors, 408, 409, 429, and 5xx, honouring
Retry-After. - There is no
Idempotency-Keyon the core API. Duplicate-safety is yours to build. - A retried tool call can execute twice. That, not the retry, is what breaks agent systems.
- Alert on the error rate over a window. A single 500 in healthy traffic is normal.
The four codes, and which two OpenAI actually documents
Start with what is in the documentation, because the absences are as informative as the entries.
| Code | Documented row | Whose | Retry? |
|---|---|---|---|
| 500 | The server had an error while processing your request | OpenAI | Yes, with backoff |
| 502 | Not documented | Usually your path | Yes, then investigate |
| 503 | The engine is currently overloaded, please try again later | OpenAI capacity | Yes, with backoff |
| 503 | Slow Down | Your traffic shape | No. Reduce your rate first |
| 504 | Not documented | Usually your path | Yes, then investigate |
The two undocumented codes are the interesting ones. OpenAI serves the API through its own infrastructure and reports internal failures as 500 or 503. A 502 or 504 reaching your client, particularly with an HTML body rather than JSON, almost always means something in between generated it: a corporate proxy, an API gateway, a service mesh, a CDN, or a load balancer with an idle timeout shorter than your request. The tell is the body. A JSON error object with a type field came from OpenAI. An HTML page did not.
Slow Down is not overload
Both 503s carry the same status code and mean opposite things, and only one of them is safe to retry. The distinction is worth the paragraph because getting it backwards actively makes your situation worse.
That is not generic backoff advice, it is a specific protocol with a specific duration. The docs add that this can occur on Pay-As-You-Go models, which are shared across all OpenAI users, and point at the Scale Tier for guaranteed capacity.
The engine is currently overloaded | Slow Down | |
|---|---|---|
| Cause | OpenAI servers experiencing high traffic | Your rate increased sharply |
| Who else sees it | Everyone on shared capacity | Only you |
| Correct response | Backoff and retry | Cut your rate to its previous level |
| Duration | Until capacity frees up | At least 15 minutes at the reduced rate |
| Retrying at full rate | Wasteful | Actively counterproductive |
| Structural fix | Scale Tier, or failover | Ramp gradually. Do not step-change your traffic |
Retrying properly
The SDKs already do most of this. Both the Python and Node clients state it identically: certain errors are automatically retried two times by default with a short exponential backoff, covering connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit, and anything 500 or above. Retry-After is honoured. Timed-out requests are retried too.
from openai import OpenAI
# Defaults, for reference: max_retries=2, timeout=600s total / 5s connect,
# initial retry delay 0.5s, max retry delay 8s, Retry-After capped at 120s.
interactive = OpenAI(max_retries=1, timeout=45.0) # a human is waiting
batch = OpenAI(max_retries=8, timeout=900.0) # nobody is waiting
When you write the loop yourself, OpenAI's own guidance is explicit about jitter: honour Retry-After when present, and when it is absent, "use exponential backoff with jitter and limit the number of retries".
- Retry 500, 502, 503 overload, and 504. Bounded, jittered, capped.
- Do not retry 503 Slow Down at the same rate. Cut the rate first, then resume.
- Never retry a 4xx other than 408, 409, and 429. They cannot succeed and the retries just delay the real error.
- Never retry the billing 429s. OpenAI states directly that retrying billing, spend, or quota errors will not restore access.
- Cap total elapsed time, not just attempt count. Eight attempts with a long tail can exceed any user's patience and any upstream timeout.
The agent problem: retrying a call that already did something
This is the part that separates an agent workload from a chat completion, and it needs saying plainly.
Why it matters: a 500 tells you the request failed, not that nothing happened. In a chat completion the worst case is a duplicated generation, which costs tokens and nothing else. In an agent loop, the model may have already emitted a tool call that your executor already ran. Retrying the API call replays the turn, the model calls the tool again, and your side effect happens twice. Two payments, two branches, two emails.
import hashlib, json
def tool_key(turn_id: str, name: str, args: dict) -> str:
payload = json.dumps(args, sort_keys=True)
return hashlib.sha256(f"{turn_id}:{name}:{payload}".encode()).hexdigest()
def execute(turn_id, name, args):
key = tool_key(turn_id, name, args)
cached = results.get(key)
if cached is not None:
return cached # the retry sees the first result, not a second execution
out = TOOLS[name](**args)
results.put(key, out, ttl=86400)
return out
- Key on the turn, not the request. A retried API call is a new HTTP request but the same logical turn.
- Classify your tools. A file read is safely repeatable. A payment, a merge, an email, and a delete are not. Only the second group needs the cache, and only that group is worth the complexity.
- Persist the ledger. An in-memory dict does not survive the process restart that a 500 storm often triggers.
- Use background mode for long work. OpenAI documents
background: truewith polling for exactly this: the work continues server-side and you resume against a response ID rather than replaying a whole turn. Cancellation is idempotent even when nothing else is.
Is it OpenAI, or is it you?
Ninety seconds of triage, in order, before you change anything.
Check the status page
status.openai.com reports APIs separately from ChatGPT and Codex, each with its own components. An open incident on the API component ends the investigation. For calibration, the API surface showed 99.94% trailing uptime when we checked, with incidents on 11 August and a cluster through late July including latency issues on the 24th and an error-code-specific incident on the 29th.
Look at the response body, not just the code
curl -sS -o /tmp/body -w '%{http_code} %{content_type}\n' \
https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.6-luna","input":"ping","max_output_tokens":16}'
head -c 300 /tmp/body
A JSON object with an error.type came from OpenAI. An HTML page, or a body naming Cloudflare, nginx, or an ELB, came from something in your path. That single check resolves most 502 and 504 mysteries.
Bypass your own infrastructure
Run the same call from a laptop on a plain network. If it works there and fails from your cluster, you have found the layer. Corporate proxies, egress gateways, and load balancers with 60-second idle timeouts are the usual suspects, and none of them are visible from inside your application logs.
Measure the rate, over a window
A single 500 in a thousand calls is normal operation for any large distributed service. Alert on a sustained ratio, for example above two percent over five minutes, and record the model and the endpoint alongside it. Overload is often model-specific, and knowing that changes your fallback from a guess into a decision.
Questions people ask
What does "The server had an error while processing your request" mean?
It is OpenAI's documented 500: an internal failure on their side while handling your request. It is not caused by your key, your quota, or your prompt. Retry it with exponential backoff, and if it persists check the status page and contact support with the request ID. Note that the "Sorry about that!" suffix widely quoted online is not in the current documentation.
Is a 503 from OpenAI the same as a 500?
No, and there are two different 503s. "The engine is currently overloaded, please try again later" is capacity and behaves like a 500: back off and retry. "Slow Down" is OpenAI telling you specifically that your own rate increased sharply, and the documented fix is to reduce your request rate to its original level, hold it there for at least 15 minutes, and then increase gradually. Retrying that one at full rate makes things worse.
Why am I getting a 502 or 504 from the OpenAI API?
Neither code appears in OpenAI's documentation, which strongly suggests they did not come from OpenAI. Check the response body: a JSON object with an error.type came from the API, while an HTML page or a body naming Cloudflare, nginx, or a load balancer came from something in your own network path. Proxies and load balancers with idle timeouts shorter than a long generation are the usual cause.
How many times do the OpenAI SDKs retry by default?
Twice, in both the Python and Node clients, with a short exponential backoff. The retried set is connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit, and anything 500 or above, and the SDKs honour the Retry-After header. Configure it with max_retries in Python or maxRetries in Node.
Does the OpenAI API support an Idempotency-Key header?
Not on the core inference endpoints. The only place OpenAI documents idempotency keys is the separate Agentic Commerce API, where a parameter mismatch returns idempotency_conflict with a 409. On /v1/responses and /v1/chat/completions you have to build duplicate safety yourself, and the right place for it is the tool executor rather than the API client.
Can retrying a failed request cause a tool to run twice?
Yes, and this is the main hazard for agent workloads. A 500 tells you the request failed, not that nothing happened. If the model already emitted a tool call that your executor ran, replaying the turn can run it again. Key a result cache on the logical turn plus the tool name and arguments, and apply it to the tools with real side effects rather than to every read.
Sources
Every figure above was read from these pages on August 2026. Vendors reprice without notice; if you find a stale number, tell us.
- OpenAI API error codes 500 and the two 503 rows, and the absence of 502 and 504
- OpenAI rate limits Retry-After handling and the project-scoped rate-limit headers
- openai-python on GitHub default of 2 retries and the retried status set
- OpenAI background mode long-running requests, polling, and idempotent cancellation
- OpenAI status component split and recent incident history