Errors
Error code reference and handling guide.
Error format
Every error response carries a JSON body in this shape:
{
"error": {
"code": 20002,
"message": "Missing required parameter",
"request_id": "req_8a4f0d2e-1c8b-4f1a-9e2d-3b7c5a6f0a1b"
}
}| Field | Description |
|---|---|
code | 5-digit numeric code. The leading digit is the category (1xxxx auth, 2xxxx validation, …). |
message | Human-readable explanation. May embed request-specific context (parameter names, balance, etc.). |
request_id | Unique per request. Optional — present whenever the gateway has assigned one; include in support tickets. |
The HTTP status code reflects the category (401 / 400 / 402 / 429 / 500 / 502 / 503 / 504); the code field gives you the precise reason.
For failed tasks, the same envelope is returned inside the polling response under error — see the model docs' Response section.
Code catalog
1xxxx — Authentication (HTTP 401 / 403)
code | HTTP | Cause |
|---|---|---|
10001 | 401 | Missing Authorization header |
10002 | 401 | Authorization header is not Bearer <key> |
10003 | 401 | API key invalid |
10004 | 401 | API key has been revoked |
10005 | 401 | Sign-in required (session-auth surfaces) |
10006 | 403 | Request origin not allowed |
2xxxx — Validation (HTTP 400)
code | Cause |
|---|---|
20001 | Request body is not a JSON object |
20002 | Required parameter missing — message says which |
20003 | Parameter value invalid (type / range / enum) |
20004 | model not supported on this endpoint |
20005 | size not supported by this model |
20006 | quality not supported by this model |
20007 | prompt exceeds maximum length |
3xxxx — Billing (HTTP 402 / 400)
code | HTTP | Cause |
|---|---|---|
30001 | 402 | Insufficient credits |
30002 | 400 | Cannot determine pricing for this model |
4xxxx — Resource (HTTP 404)
code | Cause |
|---|---|
40001 | Task not found, or belongs to another user |
5xxxx — Rate limit (HTTP 429)
code | Cause |
|---|---|
50001 | Rate limit exceeded — see Retry-After |
6xxxx — Server internal (HTTP 500)
code | Cause |
|---|---|
60001 | Failed to persist task — credits refunded |
60002 | Failed to start workflow — credits refunded |
60099 | Generic internal error |
7xxxx — Capacity (HTTP 503)
code | Cause |
|---|---|
70001 | Workflow service unavailable — retry |
70002 | Database unavailable |
8xxxx — Workflow execution (returned inside the polling response body when status="failed")
HTTP status for GET /api/v1/tasks/{id} is always 200 when the task is
found. The codes below appear only inside error.code of the response
body — they are never the HTTP response status.
code | Cause |
|---|---|
80001 | Upstream submission failed (5xx / network on submit) |
80002 | Polling timeout (wall-clock cap reached) |
80003 | Upstream returned a terminal failure |
80004 | Upstream completed but returned no URLs |
80005 | Failed to persist generated files |
80006 | Content policy violation. A prompt, reference image, reference video, or generated output may have triggered a safety check. If that model documents content_filter, API-key callers can try "content_filter": false for less restrictive moderation; it does not turn moderation off. |
80007 | Upstream rejected the input as invalid |
80008 | Task canceled |
80009 | Legacy task only: an earlier worker could not verify exact token billing evidence and refunded the task. Current GPT Image 2 Official tasks instead complete and charge the admission reservation when images exist but token evidence is unavailable. |
The 8xxxx codes are written to the task by the worker; polling returns them under error.code once status="failed".
Handling 80006 content-policy errors
80006 is a cross-model workflow code. It does not, by itself, identify a
particular model, provider, or moderation stage as the cause. A safety check
may have rejected any of these:
- the prompt;
- a reference image;
- a reference video; or
- the generated image or video.
Do not retry the same payload unchanged. First remove or rephrase sensitive content and verify that every reference image and reference video is suitable. Even when all submitted inputs are acceptable, a generated output can still trigger the code.
For models whose own API documentation lists the boolean content_filter
parameter, direct API-key requests can also try the less restrictive route:
{
"model": "<a model that supports content_filter>",
"prompt": "<your revised prompt>",
"content_filter": false
}This option is model-specific, not a global request parameter. It selects a
less restrictive moderation path; it does not disable safety review. The
hosted Playground keeps moderation enabled, and upstream policy checks still
apply, so a request can still return 80006. Check the selected model's
parameter list before sending it.
Refund behavior depends on where the verdict occurred and on the selected
model's documented policy. Check the failed task's usage.credits: 0 means
the reservation was fully refunded; a positive value means a post-generation
charge was retained.
Recommended handling
import requests, time
def safe_call(method, url, **kwargs):
for attempt in range(3):
r = requests.request(method, url, **kwargs)
body = r.json()
if r.status_code == 200:
return body
if r.status_code == 429:
time.sleep(int(r.headers.get('Retry-After', '5')))
continue
if r.status_code in (502, 503, 504):
time.sleep(2 ** attempt)
continue
raise RuntimeError(
f"{body['error']['code']}: {body['error']['message']}"
)
raise RuntimeError("max retries exceeded")What to retry vs not
| HTTP | Retry? |
|---|---|
| 200 | n/a |
| 400 / 401 / 402 / 404 | ❌ Fix the request |
| 429 | ✅ With Retry-After |
500 — 60001 / 60002 | ⚠️ Credits refunded, re-submit |
500 — 60099 | ✅ Idempotent retry safe |
| 502 / 503 / 504 | ✅ Exponential backoff |
Support
When reporting an issue, include:
- The
request_idfrom the response - The full request URL + method
- Approximate timestamp (UTC)
Email: [email protected]