Build with the API
Errors and how to handle them
A call that succeeds is answered 200. A call that is refused or fails is answered with another status and a JSON object that says what happened. Quote the x-request-id response header when you ask support about a call.
The error object#
On every route except /v1/messages, the body is this error object, which OpenAI's clients read as their own:
{
"error": {
"message": "the account does not have enough credit for this request",
"type": "insufficient_quota"
}
}
messagesays what to change, in words.typeis the kind of error, for code to branch on.codeis present where a refusal has a more specific cause, such as which limit was reached.paramis present on a400and names the request field at fault.
/v1/messages answers in the form Anthropic's clients read instead, {"type": "error", "error": {"type": "...", "message": "..."}}. See Using Anthropic's client.
Statuses#
| Status | Type | When | What to do |
|---|---|---|---|
| 400 | invalid_request_error | The request is malformed, sets a parameter the model does not accept (param names it), or carries a conversation longer than the model can take. | Fix the request. Retrying it unchanged fails again. |
| 401 | authentication_error | No key, or a key that is unknown, expired or removed. | Send a valid key. |
| 402 | insufficient_quota | Your credit, the key's spending limit or the account's monthly budget does not cover what this call could cost. code is key_spend_limit or monthly_budget when a limit refused it, and absent when credit ran out. | Add credit or raise the limit. Retrying does not help until you do. |
| 403 | permission_error | The key is restricted to other models, or the model may keep data and sharing data with it is not allowed: code is data_sharing_not_allowed (the person can allow it) or data_sharing_forbidden (their organisation does not allow it). | Use a model the key may call or one that keeps no data, a different key, or allow the model under Settings, Models. |
| 404 | model_not_found | There is no such model, or it has no price and is not for sale. | Take an id from the model list. |
| 404 | not_found_error | On /v1/invocations and /v1/files: no such file or conversation for this key. A file of another conversation answers the same. | Use a file reference an earlier answer gave this key. |
| 409 | idempotency_error | A call with this Idempotency-Key is still running, or it finished and its stored answer is gone. | Wait and retry, or send a new key. See Safe retries. |
| 410 | gone | The file is no longer kept. | Make it again. |
| 413 | invalid_request_error | The request body is past the size limit. | Send less. |
| 429 | rate_limit_error | Too many calls per minute or at once, or the model is busy. code is key_rate or workspace_concurrency when a limit refused it. | Wait the seconds in the Retry-After header. See Rate limits. |
| 500 | server_error | Something failed inside the service. The response says nothing about how. | Retrying is safe but may fail again. |
| 502 | upstream_error | On /v1/invocations: the model delivered something other than it said, or too much of it. Nothing was kept or charged. | Retry, or choose another model. |
| 503 | server_error | The model is temporarily unavailable, or a model is not for sale right now. | Retry shortly. |
| 507 | storage_full | On /v1/invocations: the storage quota of the person whose file the result would be is full. Nothing ran and nothing was charged. | Delete files or chats under Settings, Storage, then retry. |
| 529 | overloaded_error | On /v1/messages only: the model is temporarily unavailable. | Retry shortly. |
On /v1/messages the types are the ones Anthropic's clients expect, for the same statuses: invalid_request_error, authentication_error, billing_error (402), permission_error, not_found_error, request_too_large (413), rate_limit_error, api_error (500) and overloaded_error, which is status 529 instead of 503.
Errors in the middle of a stream#
A streamed call that has started is already 200. If it fails after that, the failure arrives as an event and the stream ends. See Streaming.
Handle them in code#
Retry what is temporary, with a pause that grows (the Python example honours Retry-After), and stop on what a retry cannot fix.
import os
import time
import openai
from openai import OpenAI
client = OpenAI(base_url="https://sven.swedishembedded.com/v1", api_key=os.environ["SVEN_API_KEY"], max_retries=0)
def ask(question: str, attempts: int = 5) -> str:
for attempt in range(attempts):
try:
reply = client.chat.completions.create(
model="MODEL_ID",
messages=[{"role": "user", "content": question}],
)
return reply.choices[0].message.content
except openai.APIStatusError as error:
retryable = error.status_code in (429, 500, 503)
if not retryable or attempt == attempts - 1:
raise
wait = float(error.response.headers.get("retry-after", 2**attempt))
time.sleep(wait)
raise RuntimeError("unreachable")
If a retry could run a call twice, send an Idempotency-Key so it cannot be charged twice. See Safe retries.