Errors, and what to do
Every error has a stable code. Branch on the code, not the message. This table is built from the API's own code list.
The shape
Section titled “The shape”Every error body is JSON:
{ "error": "Not enough credits.", "code": "INSUFFICIENT_CREDITS", "request_id": "req_...", "needed": 63, "balance": 12}codeis stable and machine-readable. Branch on it. Accept a code you do not know and treat it by its HTTP status.request_idis also theX-Request-Idheader. Quote it when you ask diffusr for help. Send your ownX-Request-Id(1 to 64 letters, digits,_or-) to choose it.- Some codes add detail:
issues(VALIDATION_FAILED, PREFLIGHT_FAILED),neededandbalance,budget,scope,limit,retry_after_seconds,field,index. 429and503answers carry aRetry-Afterheader: seconds to wait.- A refused request is never charged.
- MCP tool errors start with
[CODE]and end with arequest_id:line.
Every code
Section titled “Every code”| Code | HTTP | What it means | Retry? | What to do |
|---|---|---|---|---|
UNAUTHORIZED | 401 | Missing, malformed or unknown API key. | No | Send Authorization: Bearer <key>. Copy the key again from Developers in the app. |
KEY_REVOKED | 401 | This key was revoked. Make a new one on the Developers page. | No | Make a new key on the Developers page and use that. |
KEY_EXPIRED | 401 | This key passed its expiry date. Make a new one. | No | Make a new key on the Developers page. |
SCOPE_DENIED | 403 | The key does not have the scope this call needs. | No | Use a key that has the scope the route names, or make a new key with it. |
MODEL_NOT_ALLOWED | 403 | The key is limited to other models. | No | Pass a model the key may use (the default model counts), or use another key. |
TEST_MODE_UNSUPPORTED | 403 | This call is not available with a test key. | No | Use a live key for this call. |
ACCOUNT_BLOCKED | 403 | The account is blocked. Contact support. | No | Stop. Tell the user to contact diffusr. |
FORBIDDEN | 403 | Not allowed (a refusal that has no more specific code). | No | Read error for the reason. Do not retry as is. |
VALIDATION_FAILED | 422 | The input did not match the schema; issues lists each field and why. Nothing was made, nothing charged. | No | Read issues: each has a field path and a reason. Fix those fields and send again. Nothing was charged. |
INVALID_JSON | 422 | The body was not a JSON object. | No | Send a JSON object with Content-Type: application/json. |
INVALID_REQUEST | 400 or 422 | The request was understood but cannot be done as sent (a refusal that has no more specific code). | No | Read error, change the request, send again. |
PREFLIGHT_FAILED | 422 | The job cannot run as described (for example a missing input); issues lists why. Nothing was charged. | No | Read issues for what is missing or unusable, fix it, send again. Nothing was charged. |
CALLBACK_URL_INVALID | 422 | callback_url is not usable: it must be a public https address with no password. | No | Use a public https:// address with no username or password. |
CALLBACK_NOT_RETRYABLE | 409 | That callback event can’t be retried now: it was delivered, is still being tried, or is out of manual retries. | No | Check the event in GET /callbacks. Only a FAILED event with manual retries left can be retried. |
REFERENCE_UNREACHABLE | 422 | A reference file could not be fetched. | No | Make the link public and reachable without a login, or upload the file with POST /uploads. |
REFERENCE_TOO_LARGE | 422 | A reference file is over the model’s size or length limit. | No | Send a smaller or shorter file. Limits are on the Uploads and media page. |
REFERENCE_UNSUPPORTED | 422 | A reference file is the wrong kind for this model. | No | Send the right kind of file: a picture for image_urls, audio for audio_urls, video for video_url. |
REFERENCE_FORBIDDEN | 403 | A reference points at a file the caller may not use. | No | Use a link to your own upload or result, or any public link. Do not use asset:// links. |
NOT_FOUND | 404 | No such id, or it belongs to someone else (or to the other key mode: test vs live). | No | Check the id. A test key cannot see live results, and a live key cannot see test results. |
IDEMPOTENCY_CONFLICT | 409 | This Idempotency-Key was already used for a different request. | No | Use a new Idempotency-Key for a different request. Reuse the old key only to repeat the exact same request. |
CONFLICT | 409 | The request conflicts with the current state (a refusal that has no more specific code). | No | Read error, fetch the current state, then decide. |
INSUFFICIENT_CREDITS | 402 | Not enough free credits; needed and balance say by how much. | No | Tell the user. needed and balance say how short they are. They can top up in the app. |
allowance_exceeded | 402 | A team member’s limit or the team pot is used up (legacy lowercase code, kept for existing clients). | No | Tell the user. A team limit is used up. |
BUDGET_EXCEEDED | 402 | The key’s or account’s daily or monthly API budget would be passed; budget has the window and when it frees up. | No | Tell the user. budget.resets_at says when the window frees up. Do not retry before then. |
RATE_LIMITED | 429 | Too many requests of this kind this minute. | After Retry-After | Wait Retry-After seconds, then send the same request again (same Idempotency-Key). |
CONCURRENCY_LIMIT | 429 | Too many jobs queued or running for this key or account. | After Retry-After | Wait Retry-After seconds, or wait for a running job to finish. The request was refused, not queued. |
PROVIDER_BUSY | 503 | Our capacity at the model’s supplier is full. Not the caller’s fault; try again. | After Retry-After | Wait Retry-After seconds, then retry. Not your fault; nothing was charged. |
AUTH_RATE_LIMITED | 429 | Too many failed sign-in attempts from this address. | After Retry-After | Stop sending bad keys. Wait Retry-After seconds. |
KEY_LIMIT | 429 | The key hit its own limit (for example how many keys an account may hold). | After Retry-After | Revoke keys you do not use, or wait Retry-After seconds before making more. |
TEST_LIMIT | 429 | A test key hit its own cap (per minute or per day). Wait, or use a live key. | After Retry-After | Wait Retry-After seconds, or use a live key. |
UPLOAD_QUOTA | 429 | Too many uploads in the last 24 hours. | After Retry-After | Wait Retry-After seconds. Reuse a file_url you already have instead of uploading again. |
STORAGE_QUOTA | 413 | The account’s stored upload bytes are at the cap; uploads clear on their own. | After Retry-After | Wait: uploads clear on their own after their retention time. |
TOO_LARGE | 413 | The request or file is too large (a refusal that has no more specific code). | No | Send a smaller request or file. |
WALLET_BUSY | 503 | The wallet was locked by another request. Retry at once. | Yes, at once | Retry at once with the same Idempotency-Key (Retry-After is 2 seconds). |
API_PAUSED | 503 | New API starts are paused for everyone. Runs already started finish. | After Retry-After | New starts are paused. Wait Retry-After seconds. Dry runs still answer. |
MODEL_PAUSED | 503 | This model is paused for new API starts. | After Retry-After | Use another model, or wait Retry-After seconds. |
PROVIDER_PAUSED | 503 | This model’s supplier is paused for new API starts. | After Retry-After | Use another model, or wait Retry-After seconds. |
UNAVAILABLE | 503 | A service we depend on is not available right now (a refusal that has no more specific code). Retry later. | After Retry-After | Wait Retry-After seconds if present (else a minute), then retry with the same Idempotency-Key. |
INTERNAL_ERROR | 500 | Something went wrong on our side. Quote the request_id to support. | After Retry-After | Retry once with the same Idempotency-Key. If it keeps failing, quote request_id to diffusr. |
Retrying safely
Section titled “Retrying safely”Retry only the codes marked “After Retry-After” or “Yes, at once”, and always with the same Idempotency-Key. If the first try had already been accepted you get that job back (idempotent_replay: true) and are not charged twice.