- API request errors — the HTTP response to a synchronous API call (authentication, billing, malformed requests, missing resources). See API request errors.
- Prediction failure codes — a request was accepted and queued, but the prediction itself ended in
status: "failed". The failure is described by theerrorobject on the prediction, which you get from the prediction status endpoints, from webhook deliveries, and from the result endpoint. See Prediction failure codes.
Prediction failure codes
A failed prediction carries anerror object:
Failed predictions are not charged; any credits reserved for the request are released.
A prediction that has not failed carries
error: null. See Migration note if you integrated before 17 August 2026.
Where the error reaches you
The sameerror object is published on every channel, so you can read it wherever you already look:
Reading a failure from the result endpoint
Asking for the output of a prediction that failed returns400 with the failure that caused it, under the request-level code PREDICTION_FAILED:
error.codeisPREDICTION_FAILED, an API request error meaning “the prediction you asked for the output of did not produce one”;error.detailsis the prediction’s ownerrorobject — identical to what/statusreports for the same request, so the two endpoints can never disagree about why it failed. Branch onerror.details.reasonanderror.details.retryable.
error.message repeats the prediction’s message, so a client that only ever reads the top-level message still gets something useful.
Two timestamps, two meanings. The top-level timestamp is when this HTTP response was produced; error.details.timestamp is when the prediction failed. For a prediction you fetch days later, they are days apart. Read the inner one whenever you mean the failure.
The official client libraries unpack this for you: result() raises an error whose code, reason and retryable are the prediction’s own, identical to what subscribe() raises for the same failure.
A prediction that is still queued or running, or one that was cancelled, keeps returning the same generic 400 it always has.
Deciding whether to retry
Readretryable. It answers exactly one question — will submitting this identical request again have a different outcome? — and it is independent of code: the same code can be retryable in one failure and not in another.
retryable is optional. When it is absent, fall back to the per-code default in the table below. That is the behaviour Sunra had before this field existed, so falling back is always safe; it is simply less precise.
code
reason
reason names the specific cause behind code. Use it for metrics, routing and support diagnostics; use retryable for the retry decision.
Every reason published today has its own section below, and its anchor is the reason itself — #input_fetch_failed, #moderation_blocked and so on — so an error report can link straight to what it means.
input_validation_failed
code: invalid_input · retryable: false
The request failed Sunra’s own schema or parameter validation. The message names the offending field.
What to do: fix the named field. The same request will keep failing.
provider_rejected_input
code: invalid_input · retryable: false
The model provider rejected one or more input parameters. Where the provider tells us which, the message says so; some providers only report that the input was unacceptable, and we say exactly that rather than guessing.
What to do: review your parameters against the model’s schema — a value out of range, an unsupported combination, an aspect ratio or duration the model does not accept.
input_fetch_failed
code: invalid_input · retryable: false or true
An input file referenced by URL could not be fetched. This is the one reason whose retryable genuinely varies, so read the field rather than assuming:
false— the host rejected us: a4xx, an address we are not permitted to fetch from, a redirect, or a file over the size limit;true— the host was momentarily unreachable: a5xx, a timeout, or a DNS failure.
message echoes the URL you submitted so you can tell which input failed — with its query string removed, so credentials carried in a presigned URL are never reflected back to you:
retryable is false, check that the URL is publicly reachable and that a presigned link has not expired. When it is true, retry.
moderation_blocked
code: unsafe_content · retryable: false
Blocked by the model provider’s content safety system — either the prompt and input media going in, or the generated output coming back.
What to do: change the prompt or the media. Resubmitting the same content will be blocked again.
provider_rate_limited
code: service_provider_error · retryable: true
The model provider is rate limiting requests.
What to do: retry with backoff, or route to another model.
provider_unavailable
code: service_provider_error · retryable: true
The model provider failed to serve the request.
What to do: retry later, or route to another model.
provider_timeout
code: task_timeout · retryable: true
The prediction did not complete within the allowed time.
What to do: retry — a lower-load period, or a smaller request (shorter duration, lower resolution), improves the odds.
provider_account_error
code: internal_server_error · retryable: false
Our own account with the model provider has a problem — billing, credentials, or a permanent quota. This is our fault, not your input’s.
What to do: nothing on your side; retrying will not help, and we are alerted automatically. Route to another model if you need the capacity now.
endpoint_misconfigured
code: internal_server_error · retryable: false
This model endpoint is misconfigured on our side.
What to do: nothing on your side; retrying will not help, and we are alerted automatically. Contact support with the request_id if it is urgent.
queue_enqueue_failed
code: internal_server_error · retryable: true
The prediction could not be placed on the queue.
What to do: submit the request again.
reaped_stalled
code: internal_server_error · retryable: true
The prediction stalled and was terminated.
What to do: submit the request again.
Unknown values
Bothcode and reason are open sets. New values are added as we classify more failures, without a breaking-change announcement. Your integration must not crash, drop the error, or reject the payload when it sees a value it does not recognise.
- Unknown
reason— treat it as ifreasonwere absent, and decide usingretryable(or the per-code default). Keep the raw value in your logs; it is the fastest way for support to identify the failure. - Unknown
code— treat it asinternal_server_error. One sentinel value is worth knowing by name:unknown_error_code, which Sunra emits when a prediction failed but no classification could be recovered for it.
Migration note: error is null when there is no error
Effective 17 August 2026. Theerror object has one representation on every channel. Three differences between them are gone:
errorisnullwhen the prediction did not fail.GET /v1/predictions/{prediction_id}used to answer with an empty object —"error": {}— on every succeeded, queued and cancelled prediction. It now answers"error": null, which is what the queue status endpoint already did. If you test for emptiness (Object.keys(response.error).length === 0), replace that with a null check (response.error === null).- A failure always carries a non-empty
codeandmessage. Where a failure recorded something we cannot classify, you now get theunknown_error_codesentinel and a generic message, rather than a field that is missing, empty or not a string. - Failures recorded as plain text reach you as text. A handful of predictions from April 2026 stored their error as a bare string.
GET /v1/predictions/{prediction_id}used to drop it, and the queue status endpoint used to replace it with the sentinel message; both now publish it asmessageundercode: "unknown_error_code".
error was already on every one of these responses, and only its value changed. Webhook deliveries are untouched — they were the shape the other channels converged on — and error continues to be absent from a succeeded delivery rather than sent as null.
Compatibility window. There is no dual-emission period; the API stopped producing "error": {} on that date. If you replay or reprocess payloads you captured before it, treat null and {} as the same thing until that stored data ages out.
Upcoming change: some failures will get a more specific code
Today a large share of failures are reported as service_provider_error, including many that are neither transient nor the provider’s fault. As we classify providers one at a time, those failures move to the code that actually describes them:
- a provider deterministically rejecting your input becomes
invalid_input(previouslyservice_provider_error); - a problem on Sunra’s side, such as a misconfigured endpoint or our own provider account, becomes
internal_server_error(previouslyservice_provider_error); - an input file we could not fetch becomes
invalid_input(previouslyinternal_server_error).
code value is being introduced — the five values above remain the complete set of classified codes. What changes is which of them a given failure receives, and it changes gradually, per provider. If you branch on code, this is a good moment to move that logic onto retryable and reason, which describe the failure directly and are not affected by the reclassification.