OpenAI API errors look diverse, but only five layers need to be separated first: did the request leave the client, is the identity correct, are the address and model correct, are the parameters valid, and have quota or rate limits been hit. Troubleshoot in order and most problems can be located within minutes.
This article breaks down 401, 403, 404, 400, 429, and 5xx by status code, with minimal reproduction commands, retry strategy, and a fixed troubleshooting sequence. Model names and gateway configuration are subject to the on-site model pricing and integration documentation.
Note: OpenAI, GPT, and ChatGPT are trademarks of their respective owners. This article uses common API behavior as of October 2026. Error codes and quota rules are subject to official documentation and actual responses.
1. Save three pieces of evidence first
Before troubleshooting, save these three things:
- the HTTP status code;
error.type,error.code, anderror.messagein the response body;x-request-idin the response headers.
The request ID is the most useful information when talking to the service provider. Without it, you can only describe "a failure at around such-and-such time"; with it, the provider can find the exact request, upstream, and billing.
| Status code | Common type | First judgment |
|---|---|---|
| 400 | invalid_request_error |
A problem with a parameter, the JSON, or the context length |
| 401 | authentication_error |
The key is missing, wrong, or no longer valid |
| 403 | permission_error |
The key has no access to that model or project |
| 404 | not_found_error |
The Base URL or model name is wrong |
| 429 | rate_limit_error / insufficient_quota |
Rate limiting, or insufficient balance |
| 500/502/503/504 | server_error |
Upstream failure or a network interruption |
2. 401 and 403: identity and permission
The core of 401 is "the server does not recognize this key." Common causes:
- the request header is missing
Authorization: Bearer; - the key was copied with extra spaces or line breaks, or was truncated;
- the key was deleted or rotated, or its project was disabled;
- a gateway key was sent to the official address, or an official key to the gateway address;
- an environment variable is misspelled, so an empty string is actually sent.
403 is more often "we recognize you, but you are not allowed to do this." For example, the key lacks permission for the model, the organization is restricted, or the project has not enabled the capability. Do not keep retrying on 403; check the key's project and the model permissions in the console.
A quick self-check:
curl -sS "https://api.zhongshangqihang.com/v1/models" \
-H "Authorization: Bearer $ZSQH_API_KEY" \
-w "\nHTTP %{http_code}\n"
If it lists models, the key and address are basically correct. If it still returns 401, check the key itself and the environment variable first.
3. 404: address or model does not exist
A 404 does not necessarily mean "the endpoint is retired"; more often the path is wrong. Common cases:
| Symptom | Cause | Fix |
|---|---|---|
404 page not found |
The Base URL has an extra /v1 or is missing one |
Use https://api.zhongshangqihang.com/v1 consistently, per the documentation |
model_not_found |
Model name misspelled or not enabled | Copy the model name from the model pricing page |
| 404 with a double slash in the path | An extra / when joining the URL |
Remove the duplicate slash |
| SDK returns 404 | base_url repeats the endpoint path |
Keep only one /v1 |
When troubleshooting, send a minimal request with curl first to rule out SDK URL-joining problems. If curl works but the SDK does not, the problem is usually in base_url, a proxy, or the SDK version.
4. 400: parameters and context
A 400 means the request itself is invalid; retrying is pointless. Frequent causes include:
- malformed JSON, such as a trailing comma, single quotes, or an unescaped newline;
- parameters the model does not support, such as certain sampling parameters on some models;
max_tokensabove the model limit;- input exceeding the context window, returning
context_length_exceeded; - an image whose format or size is invalid, or whose URL cannot be reached;
- an invalid tool schema missing required fields.
The order of handling: cut back to the minimal request, then add parameters back one at a time. Do not change five things at once; otherwise, when the error disappears, you will not know which change fixed it.
5. 429: rate limiting or insufficient balance
429 is the most easily misdiagnosed. It has at least two meanings:
| Error code | Meaning | Handling |
|---|---|---|
rate_limit_exceeded |
Request frequency, token rate, or concurrency exceeded | Reduce concurrency, queue requests, use exponential backoff |
insufficient_quota |
Insufficient balance or exhausted quota | Top up, change key, check project quota |
Look at the response body and headers first. retry-after tells you how long to wait; x-ratelimit-remaining-requests and x-ratelimit-remaining-tokens show how much quota remains. If the remaining amount is zero, backing off longer will not help; you need the window to reset or the limit to be raised.
A usable retry loop:
import random
import time
from openai import OpenAI
client = OpenAI(
api_key="sk-your-key",
base_url="https://api.zhongshangqihang.com/v1",
)
def chat(prompt: str, retries: int = 4) -> str:
for attempt in range(retries):
try:
resp = client.chat.completions.create(
model="gpt-5.5",
messages=[{"role": "user", "content": prompt}],
max_tokens=500,
timeout=60,
)
return resp.choices[0].message.content
except Exception as exc:
status = getattr(exc, "status_code", None)
if status not in (429, 500, 502, 503, 504) or attempt == retries - 1:
raise
wait = min(2 ** attempt, 16) + random.random()
print(f"{status}, retrying in {wait:.1f}s: {exc}")
time.sleep(wait)
raise RuntimeError("unreachable")
Retrying only helps for 429, 5xx, and network errors. Retrying 400, 401, 403, or 404 only wastes time and quota.
6. 5xx: upstream failures and network problems
500, 502, 503, and 504 usually mean the request was not written incorrectly; the upstream service is abnormal, the gateway timed out, or the network dropped. Principles:
- Retry once or twice with exponential backoff and random jitter.
- For streaming requests, determine whether partial content has already arrived; partial output may already be billed.
- Idempotent operations can retry automatically; non-idempotent operations need a deduplication key.
- During a large-scale 5xx incident, check the provider's status page; do not blindly raise concurrency.
- Record the request ID so the provider can investigate.
If only your requests return 5xx while other teams are fine, check request body size, timeout settings, and the proxy path first.
7. A fixed troubleshooting sequence
When an error occurs, follow this order without skipping steps:
- Send a minimal request with curl to confirm the address and key.
- Compare the official and gateway addresses to confirm keys are not mixed up.
- Check that the Base URL contains exactly one
/v1. - Check that the model name was copied from the pricing page and is enabled.
- Remove optional parameters and confirm the minimal request works.
- Check the balance, project quota, and key cap.
- Check the 429 response headers to distinguish rate limiting from balance.
- Check the provider's status page for an upstream outage.
- Save the request ID, status code, and response body before contacting support.
8. FAQ
Does a 429 always mean calls are too fast?
No. A 429 may mean frequency or concurrency exceeded, or it may mean insufficient balance. Check error.code and the response headers; do not slow everything down by default.
Does changing the key fix a 401?
Changing the key can rule out a problem with the key itself, but if the address is mixed up, the environment variable is empty, or the project lacks permission, no number of keys will help. First confirm where the request is actually being sent.
Does a 404 mean the model was retired?
In most cases, the Base URL or model name is wrong. Call /v1/models with curl first, then check the model name against the pricing page.
Can 5xx errors be retried indefinitely?
No. Set a maximum retry count and a total timeout to avoid piling up requests during an outage. For streaming requests, also consider that partial output may already be billed.
How do I tell a gateway error from an official error?
Check the response body format and request ID first, then call both the official and gateway addresses with the same key and same model. The layer that reproduces consistently is where the problem lies.
Next steps
Set up the minimal request, usage logging, and retry strategy before sending production traffic. If you need RMB top-ups and a unified multi-model endpoint, start by registering for the ZSQH AI Gateway; model names and prices are subject to model pricing.
Related reading:
