Ten Sume job error categories and which ones are worth a retry
Sume failed jobs carry a category such as validation, quota or worker_timeout. Map all ten to retry, fix, top up or support in one small Python table.

A failed Sume job carries public error metadata: a category, a stage, whether it is retryable, retry-after seconds, a public reason and a next action. The Sume docs list ten common categories. Four of them are safe to retry later with the same idempotency key (queue, generation_unavailable, runtime_unavailable, worker_timeout), two need you to poll first, and the rest need a change from you before any retry.
The ten categories
The table keeps the docs' guidance and adds one column for what a script should do. Prefer the job's own retryable and next_action fields over this table when they are present.
| Category | Docs next action | Script action |
|---|---|---|
| validation | Correct the input | Stop; fix the request |
| auth | Examine the API key and workspace access | Stop; alert |
| quota | Add funds, or decrease the request cost | Stop; top up or shrink |
| queue | Retry later with the same idempotency key | Retry later |
| generation_unavailable | Retry later | Retry later |
| generation_rejected | Examine events; correct unsupported input | Stop; read events |
| generation_timeout | Poll the status, or retry later | Poll first |
| runtime_unavailable | Retry later; not aggressively | Retry with a long delay |
| worker_timeout | Poll the status, or retry later | Poll first |
| internal | Examine events; contact support with the request or job id | Stop; open a ticket |
Why poll before you retry
A timeout category does not mean the work was lost. The job record may already have moved on, and a resubmit would create a second paid job. Read GET /v1/jobs/{id} first, then decide. When you do retry, send the original Idempotency-Key. The docs say not to retry unsafe submit requests without one.
The mapping in code
The function returns a short action word. Unknown categories fall through to support, so a new category never retries blindly.
ACTIONS = {
"validation": "fix_input",
"auth": "fix_auth",
"quota": "top_up",
"queue": "retry_later",
"generation_unavailable": "retry_later",
"generation_rejected": "read_events",
"generation_timeout": "poll_first",
"runtime_unavailable": "retry_slowly",
"worker_timeout": "poll_first",
"internal": "support",
}
def next_step(job_error: dict) -> str:
if job_error.get("retryable") is False:
return "stop"
return ACTIONS.get(job_error.get("category", ""), "support")
print(next_step({"category": "worker_timeout"})) # poll_first
print(next_step({"category": "quota"})) # top_up
print(next_step({"category": "brand_new"})) # supportLog the request id
Every error body has a request id that is safe to share with support. Do not include API keys, signed URLs, raw media URLs or private ids in a ticket.
Queue and capacity errors are not job errors
Do not mix the job categories with the submit errors. 402 insufficient_credits, 429 queue_full, 429 rate_limited and 503 provider_capacity_exceeded come back on the submit call, before a job exists. They follow their own rules: do not retry a 402 in a loop, wait for capacity on queue_full, honor retry-after on rate_limited, and retry later with the same key on provider_capacity_exceeded.
A job category tells you what happened to an accepted job. The two lists meet in one place, the idempotency key: when the guidance says retry later, retry with the same key, so that you cannot create a second paid job.
GET /v1/jobs/{id}/events returns a public timeline: job.created, job.queued, job.started, generation.submitted, and the terminal events. For generation_rejected and internal, read the events first. They show whether the job started and where it stopped, which is the information a support request needs along with the request id.
Sources
Related posts
More in Developers
- Self-test a Python Sume verifier: rotation, stale time, empty secret
Six asserts for a stdlib hmac verifier: new and old secret both pass, tampered body fails, 301 seconds old fails, empty secret raises. One file, no framework.
- Test an Omni edit prompt at 360p first: 23 cents vs 113 at 1080p
Edit mode on Gemini Omni Flash 1.1 takes resolution as an option. Try the edit at 360p, then render the winner at 1080p. Arithmetic for a 6 s clip.
- Test one video prompt on ten models for under $7 (Python sweep)
A 5-second, lowest-resolution sweep of one prompt over ten Sume video ids costs about $5.60 in total. The price of each row and a script that submits them.
- Test Sume retry code with a unittest fake server: 429 then 202
A stdlib fake server answers 429 with Retry-After, then 202. The test asserts your retry reuses the same Idempotency-Key and waits 7 seconds, with no sleep.
Written by Sume