Which field do I branch on in a Sume API error: code or next_action?
Branch on the HTTP status, then on error.code. Use retryable, retry_after_seconds and next_action to decide on a resend. Never match on message.

Branch on the HTTP status first, then on error.code. The code is the stable token to switch on: it matches ^[a-z0-9_]+$ and is never a sentence. Use retryable and retry_after_seconds to decide whether resending can succeed, and next_action for what to do about it. The message is for humans and may change, so log it and never match on it.
This follows Format API errors, read 2026-09-29. The envelope fields below are documented for Format run calls; the Errors and rate limits page shows a shorter envelope with code, message, request_id and details for the general API.
What is in a Sume error body?
An error object with code, message, request_id, category, stage, retryable, retry_after_seconds, public_reason, next_action and details. Each one has one job.
| Field | Use it for |
|---|---|
code | The stable token to switch on |
message | A human sentence; log it, never match on it |
request_id | Also sent as the x-sume-request-id header; quote it to support |
retryable, retry_after_seconds | Whether resending the same request can succeed, and how long to wait first |
next_action | authenticate, fix_input, add_funds, retry_later, poll_status, inspect_events or contact_support |
category, stage, public_reason | Coarser labels for dashboards and alerts |
details | Code-specific data such as required_scope or index |
What does a 4xx tell me about retrying?
On a Format run create, a 4xx means nothing ran and nothing was charged, so fix the call rather than retrying it. The docs single out one mistake: retrying a 403 insufficient_scope in a loop is the most common and most expensive mistake. Scopes cannot be added to an existing key, so the fix is to mint a new key.
On that Format run create, a failed create also releases its Idempotency-Key, so once the cause is fixed you can resend with the same key. Generation submits differ: in current code a same-key retry after 429 queue_full or 503 provider_capacity_exceeded replays that refusal, so send a new key once the cause clears.
How do I write the dispatcher?
Map the documented next_action values to your own outcomes, and fall through for anything new. The errors page says to treat the set of codes as open: new codes may appear, so handle the ones you know and fall through on the rest.
def decide(status: int, error: dict) -> str:
if error.get("retryable") is True:
return f"wait {error.get('retry_after_seconds') or 'a backoff'}, then resend"
action = error.get("next_action")
if action == "authenticate":
return "fix the key or its scopes; do not loop"
if action == "fix_input":
return "fix the request body or URL"
if action == "add_funds":
return "top up, then resend"
if action == "contact_support":
return f"quote request_id {error.get('request_id')}"
return "log message and fall through"What are the next_action values on a run receipt?
A different field on a different object: the run receipt carries next_action too, but a Format run emits only three values. It is poll_status while queued or processing, retry_later on a skipped run, and none on every terminal run.
Do failed jobs use the same fields?
A failed generation job exposes public error metadata such as category, stage, retryability, retry-after seconds, public reason and next action. The general errors page maps each job error category to a next step: validation means fix input, auth means check the API key and workspace access, quota means add funds or lower request cost, and queue means retry later (after queue_full or provider_capacity_exceeded, use a new key, as above). Internal provider payloads are never public API fields.
What should I send to support?
The request_id, the run id and the error.code. Do not send API keys, signing secrets or raw media URLs.
Sources
Related posts
More in Developers
- Which model did my AI video use? sume/auto does not say
Sume never discloses which family ran a sume/auto video: the response echoes sume/auto. What the docs say, why not to infer it, and how to pin a model instead.
- API sends both Authorization Bearer and x-api-key: 401
Sume rejects a request that carries both Authorization: Bearer and x-api-key with 401 and 'Send only one API key credential.' Neither header wins. Fix it.
- Sume webhook retry schedule: 10 attempts, then what?
Sume tries a webhook up to 10 times. Job webhooks use a fixed 30 s gap; run webhooks back off with jitter up to an hour. What happens next, and how to replay.
- Suno alternative with an API: what Sume's Music Router does
Looking for a music generator you can call from code? What Sume's Music Router takes in, returns and does not do, so you can decide if it fits.
Written by Sume