Guides
Errors and retries
Errors come back with the matching HTTP status code and the error format of the protocol you're using. Telling apart "fix the request" errors from "retry" errors is the key to a reliable integration.
Error format
OpenAI-compatible protocol:
json
{
"error": {
"message": "insufficient user quota, remaining: $0.01",
"type": "new_api_error",
"code": "insufficient_user_quota"
}
}Anthropic native protocol:
json
{
"type": "error",
"error": { "type": "invalid_request_error", "message": "..." }
}Status codes at a glance
| Status | Meaning | What to do | Retry? |
|---|---|---|---|
400 | Bad request: missing fields, wrong format for the protocol, or a parameter the model doesn't support | Fix the request based on error.message | No |
401 | API key missing, invalid, deleted or expired | Check the header and the key's status; see Authentication | No |
403 | Not enough balance or key budget, or the key isn't allowed to use this model | Top up, or adjust the key's budget and model limits | No |
404 | Path not found, usually a wrong base URL | The OpenAI SDK includes /v1; the Anthropic and Gemini SDKs don't | No |
429 | Too many requests | Lower concurrency and retry with exponential backoff | Yes |
500 / 502 | Temporary service error | Retry later | Yes |
503 | No capacity for this model right now, or the model ID doesn't exist | Check the model ID; if it's right, retry later | Yes |
504 | Timed out | Retry; for image tasks, fetch the result by task ID | Yes |
Retry strategy
Retry only on 429, 5xx and network errors. Other 4xx errors won't succeed on retry. Use exponential backoff with jitter:
retry.py
import random, time
from openai import OpenAI, APIConnectionError, APIStatusError, RateLimitError
client = OpenAI(api_key="sk-...", base_url="https://api.flyrouter.ai/v1", max_retries=0)
def chat(messages, attempts=5):
for i in range(attempts):
try:
return client.chat.completions.create(model="gpt-6.1-sol", messages=messages)
except (RateLimitError, APIConnectionError) as e:
err = e
except APIStatusError as e:
if e.status_code < 500:
raise # request, auth or balance problem; retrying won't help
err = e
time.sleep(min(2 ** i, 30) + random.random())
raise errThe official OpenAI and Anthropic SDKs already retry twice on 429 and 5xx by default. For most apps, raising max_retries is all you need.
Timeouts
- Large models can take seconds to tens of seconds before the first token, longer when reasoning. Set your client read timeout to at least 10 minutes, or use streaming.
- Image generation also needs a timeout of 10 minutes or more.
Billing and failed requests
- An estimated amount is held when a request starts and settled against actual usage when it finishes.
- Requests that fail without producing output are refunded in full.
- If a streaming request is cut off midway, the part already generated is billed.
Contact support
If a problem keeps happening, contact us with the request time, the model ID and the full error message (never include your API key).