Errors and limits
Every HTTP error code, the failed and cancelled response states, headers, rate limits and the retry policy.
HTTP errors
A refused request answers with OpenAI's error object and no envelope:
{ "error": { "message": "...", "type": "invalid_request_error", "param": null, "code": "invalid_request" } }param names the offending field when there is one. Branch on code, never on message.
| HTTP | type | code | When |
|---|---|---|---|
| 400 | invalid_request_error | invalid_request | The body is invalid; param names the field |
| 400 | invalid_request_error | unsupported_parameter | previous_response_id, conversation and similar |
| 400 | invalid_request_error | unsupported_jurisdiction | X-Jurisdiction holds us, oecd, ifrs or an unknown code |
| 400 | invalid_request_error | idempotency_key_reused | The same Idempotency-Key with a different request |
| 401 | authentication_error | invalid_api_key | The key is missing, unknown, revoked or expired |
| 402 | billing_error | insufficient_credits | The balance cannot cover the request, or there is no account |
| 402 | billing_error | spend_cap_reached | The key's monthly spend cap is reached |
| 403 | permission_error | account_suspended | The account is suspended |
| 404 | not_found_error | not_found | Unknown response, or one that belongs to another key |
| 409 | invalid_request_error | idempotency_key_in_use | The same key is still being processed |
| 409 | invalid_request_error | response_finished | Cancel on a response that has ended |
| 429 | rate_limit_error | rate_limit_exceeded | The requests-per-minute limit |
| 429 | rate_limit_error | concurrency_limit_exceeded | The in-progress responses limit |
| 500 | server_error | server_error | Anything else; never exception text |
| 503 | server_error | ledger_unavailable | The balance cannot be checked right now, so the API refuses rather than run unbilled |
A failed or cancelled response
A response that fails or is cancelled is not a refused request. It answers 200 and keeps the Responses envelope, with status and error: {code, message}:
error.code | Meaning |
|---|---|
invalid_prompt | The turn was declined: the question is outside what the service answers. Change the question |
server_error | The run could not produce an answer |
cancelled | You cancelled the response |
These are terminal states. Sending the same turn again reaches the same result, so they are not retried as such. Failed and declined runs are free (see Pricing).
Answers outside the error object
Two answers come from the layers around the API and are not in the error shape. Each carries x-request-id.
- A request that matches no route, such as an unknown path under
/v1or a method the path does not accept, answers404or405with{"detail": "..."}. - A body over 256 KiB answers
413. It is the plain textContent Too Largewhen the request declares itsContent-Length, and{"detail": "Content Too Large"}for a chunked body.
A request for an unknown response id on a known route is the exception: it is 404 not_found in the error object.
Headers
| Header | Meaning |
|---|---|
x-request-id | req_ plus 32 lowercase hex characters, on every /v1 request including errors. Quote it when you contact support |
Retry-After | Whole seconds, on every 429 and 503 |
x-ratelimit-limit-requests | The requests-per-minute limit |
x-ratelimit-remaining-requests | Requests left in the current window |
x-ratelimit-reset-requests | Time until the window resets, in OpenAI's duration form (1s, 6m0s) |
Rate limits
Limits are per key and depend on its mode. Requests are counted in one-minute windows; in-progress responses are counted from creation until the response ends.
| Key | POST /v1/responses | In-progress responses | Lookups |
|---|---|---|---|
| Live | 60 per minute | 10 | 600 per minute |
| Sandbox | 10 per minute | 2 | 60 per minute |
Past the per-minute limit the answer is 429 rate_limit_exceeded. With the in-progress count at its limit it is 429 concurrency_limit_exceeded; nothing is reserved or charged for either.
Retry policy
- Retry
429and503after theRetry-Afterseconds. Retry500too, with a short backoff. - Always reuse the same
Idempotency-Keyon the retry. A retry withoutIdempotency-Keyis a new, charged request (see Responses). - Never retry
400,401,402or403. The same request fails the same way; fix the request or the account first. - Stop after a few attempts. The quickstart samples make at most 3.