Errors and spend

Every error on the API has the same envelope, and every code is a lowercase token you can branch on. This page lists all of them for the Formats surface in one place, grouped by when they happen: before a run exists, while you read it, when the run itself fails, and when a webhook could not be delivered. Spend and rate limits are at the end.

The error envelope

FieldUse it for
codeThe stable token to switch on. ^[a-z0-9_]+$, never a sentence.
messageWritten for a human, may change. Log it; never match on it.
request_idAlso sent as the x-sume-request-id header. Quote it to support.
retryable, retry_after_secondsWhether resending the same request can succeed, and how long to wait first.
next_actionauthenticate, fix_input, add_funds, retry_later, poll_status, contact_support or none.
category, stage, public_reasonCoarser labels for dashboards and alerts.
detailsCode-specific: required_scope, workspace_id, violations[], index, status, scope, … named under each code below.

Branch on the HTTP status first, then on code. A 4xx at create means nothing ran and nothing was charged, so fix the call rather than retrying it. Retrying a 403 insufficient_scope in a loop is the most common and most expensive mistake.

Errors at create

POST /v1/formats/{handle}/{slug}/runs and POST …/bulk-runs. Nothing runs, nothing is charged, and a failed create releases its Idempotency-Key.

Statuserror.codeMeaningWhat to do
400invalid_requestThe body names none of instruction / input / previous_run_id / attachments; both output_schema and response_format; input is not an object, has more than 64 top-level keys or is over 2 MiB; generation_spend_cap_usd is 0 or over 500; model is not in the catalog; a bulk body has bad concurrency or items; a webhook URL is not public HTTPS; conflicting communication aliases.Read message and details.
400unknown_parameterA top-level field the API does not know, including thread_id. details.errors[].suggestion names the likely intended field.Rename or remove it.
400output_schema_invalidThe schema is outside the supported subset. details.violations[] lists every { path, rule, message }.Fix each violation. See Supported schemas.
400invalid_attachmentBad attachments[] item, or the media budget attachments[] shares with input URLs is exceeded.See Attachment errors.
400attachment_not_foundasset_id is unknown in this workspace.Upload it, or use a URL.
400previous_run_format_mismatchprevious_run_id was created on a different Format.Continue it on that Format.
400previous_run_not_resumableThat run left nothing to continue. details reports previous_run_status, has_thread, artifact_count.Start a fresh run.
401unauthorizedNo key, malformed key, revoked key, a key for the other host, or two credentials at once.Fix the header.
402insufficient_creditsThe workspace wallet cannot fund the run. next_action is add_funds.Top up. Retrying without doing so returns the same answer.
402organization_wallet_not_provisionedAn organization workspace with no funded wallet.An admin has to fund it.
403insufficient_scopeThe key lacks formats:write (details.required_scope), or it is a service-account key (details.reason: service_account_format_runs_unsupported).Mint a new key with the scopes; scopes cannot be added to an existing one.
403workspace_key_requiredTeam Format, personal key. details.workspace_id names the workspace.Create a key in that workspace.
404format_not_foundUnknown handle or slug, an archived Format, or one outside your key's workspace.Check the address and the key.
404previous_run_not_foundprevious_run_id is unknown or not yours.Check the id.
409format_inactiveThe Format is inactive.Activate it in the dashboard.
409format_api_trigger_disabledThe API trigger is off for this Format.Turn it on in the dashboard.
409format_run_in_progresson_active_run: "reject" and a run is already in flight.Wait, or drop reject.
409format_not_forkableYou addressed a built-in capability rather than a Format.Call a Format by Sume, or your own.
409previous_run_not_terminalThe run you want to continue is still running.Poll it, then call again.
409idempotency_conflictThat Idempotency-Key was already used with a different body. On bulk, details.queue_id names the original queue.Fix your key derivation; do not retry as is.
409idempotency_key_in_useAnother request with the same key is in flight. retryable: true.Wait about a second and resend.
413payload_too_largeThe request body is over 4 MiB (details.limit_bytes).Shrink input; send media by URL.
415unsupported_media_typeThe body was not sent as application/json (details.received_content_type).Set Content-Type: application/json.
413attachment_too_largeAn image over 30 MB, or a set over 500 MB.Resize.
429rate_limitedThe write budget for this key is spent. error.details.scope is write.Wait retry-after. See Rate limits.
502attachment_fetch_failedSume could not fetch an attachment (details.index). Despite the 5xx, it is your input: next_action is fix_input.Make the URL publicly reachable.
503studio_agent_upstream_unavailableA Sume-side outage.Retry later with the same Idempotency-Key.
4xx/5xxformat_run_failed_to_startThe run could not start for a reason with no more specific code.Read message; retry once, then contact support with request_id.

A 202 never turns into one of these later: once you hold a receipt, failures arrive on it as status: "failed".

Errors while reading

GET /v1/format-runs/{run_id}, /status, /result, /events, POST …/cancel, POST …/webhook/redeliver, GET /v1/format-run-queues/{queue_id}, and the Format reads.

Statuserror.codeMeaningWhat to do
401unauthorizedAs above.Fix the header.
403insufficient_scopeReads need formats:read; cancel and redeliver need formats:write.Mint a new key.
404format_run_not_foundUnknown run id, or a run belonging to another owner.Check the id and the key. A run you cannot see reads the same as one that does not exist.
404format_run_queue_not_foundUnknown queue, or another owner's.Same.
404format_not_foundAs above.Same.
409run_not_completedGET …/result before the run is terminal. details.status is the current status; retry_after_seconds suggests the next poll.Poll status_url, then read result_url.
409webhook_not_configuredRedeliver on a run created without a webhook_url.Nothing to redeliver.
409run_not_terminalRedeliver while the run is still running.Wait for the terminal receipt.
429rate_limitedThe read budget is spent (details.scope: read).Wait retry-after. The run keeps executing.
503studio_agent_upstream_unavailableA Sume-side outage.Retry. The run keeps executing.

A 429 or 503 inside a poll loop is transient. Abandoning the loop does not stop the run or its spend, so back off and poll again.

When the run itself fails

A run that could not finish comes back with status: "failed", error: { code, message }, and usually output_error with more detail. artifacts[] still lists everything the run generated, and output still carries whatever partial result satisfied your schema. What a failure never gets is a pointer: primary_output_url is null, so if (run.primary_output_url) stays a safe test for "the deliverable exists".

error.codeMeaningWhat to do
unattended_blockedThe run hit a gate it could not pass without a person: no avatar matched the brief, or a missing input it would have asked about in chat. message is written to be shown.Fix the input or the brief; retry with a new Idempotency-Key.
output_schema_unsatisfiedThe run finished, but its result did not match your output_schema, or referenced media it did not produce. details.rejected_urls[] or details.violations[], plus a harvested count by media type.Compare details.harvested against what your schema requires. Usually a schema demanding a file the Format never makes: loosen it to nullable, or change the instruction.
deliverable_missingThe Format is declared to produce media (io.output_kind) and this run made none.Retry; if it repeats, the input is not what the recipe expects.
primary_output_missingThe result satisfied your schema but left the primary_output_key you named empty. output carries the partial.Continue the run to fill the gap, or retry.
agent_reported_failureThe run's own accepted return_format_output said it did not deliver: an explicit-fail payload, media slots reporting failed / stand-in, or a primary that is not the Format's declared deliverable (audio or a still under a video key). output carries the ledger of what was made; primary_output_url is null.Read details.reason and output. The clips on output are real and are not regenerated by a retry; continue the run or re-fire with a new Idempotency-Key.
incomplete_assemblyThe run reached its time limit with generation jobs still unfinished, so the delivered media is not everything it paid for. details.pending_job_count and details.pending_jobs[] name them; the partial ledger is on output when your schema allows it.Continue the run with previous_run_id. The finished clips are on the thread and are not regenerated.
output_extraction_failedThe projection could not run. details.reason: harvest_unavailable means the media could not be read while the run finalized; status stays completed and the receipt fills in on the next read. details.reason: harvest_threw means the host's own harvest crashed after the run finished; the run is failed, details.thrown carries the throwing frame and build, and a run whose ledger holds none of the Format's declared media reports deliverable_missing instead.harvest_unavailable: read the run once more, then retry with a new key. harvest_threw: a host defect — report the run id; the clips on the thread are real and are not regenerated by a retry.
mcp_unavailableThe per-turn Sume MCP tools this run needed did not attach, so the host failed it before the model ran rather than run a tool-less turn (#7378). details.retryable is true and details.charged is false — no generation ran, and nothing was billed.Retry with a new Idempotency-Key. If it repeats, the tools are down, not your request.
provider_unavailableThe model's provider stream was cut and its reconnects ran out before the run produced its deliverable. Nothing about your input caused it. details.retryable is true.Retry with a new Idempotency-Key; the finished clips are on the thread and are not regenerated.
format_run_failedThe generic failure.Read message. A run that wanted to spend past its cap lands here, so compare usage.billable_amount_usd_micros with usage.generation_spend_cap_usd_micros before raising the brief.

Treat this set as open: new codes may appear, so handle the ones you know and fall through on the rest. Retry a failed run with a new Idempotency-Key; the old one is bound to the receipt you already have. When the failure left clips behind, prefer continuing the run over a fresh one.

Over a webhook, the same run arrives with status: "ERROR", outcome: "error", and error.code mirroring payload.error.code. A run that completed but could not fill your schema arrives as status: "OK", outcome: "degraded": real media, output: null.

Webhook delivery failures

A delivery outcome never changes the run. The webhook_delivery block on every receipt says what happened:

webhook_delivery.statusMeaningWhat to do
retryingAn attempt failed; next_attempt_at is the next one. HTTP 429/503 from your endpoint honour Retry-After up to one hour.Nothing, unless last_status_code is yours to fix.
failed, exhaustedTen attempts refused, timed out (10 s each), redirected, or the URL failed re-validation. last_status_code and last_error say which.Read the receipt from result_url; fix the endpoint; POST …/webhook/redeliver to replay.
Envelope with payload: nullThe receipt was over 1 MiB. error.code is payload_too_large and error.result_url says where to fetch it. status still reports the run's real outcome.Fetch result_url. A handler that assumes payload is an object will throw on your largest runs.

Full delivery rules: Runs and results.

Credits and spend

Runs spend from the workspace the key belongs to. Two gates apply, at different times:

GateWhenOn failure
WalletAt create. The workspace must be able to fund the run.402 insufficient_credits (next_action: add_funds), or 402 organization_wallet_not_provisioned. Nothing ran.
Spend capDuring the run. The run cannot spend past its effective cap.The run ends failed; usage shows how close to the cap it got.

The cap is the control you own. Every Format carries one (generation_spend_cap_usd_micros on the Format; $400 when it never set one), and generation_spend_cap_usd on the request names this run's own ceiling up to the $500 platform maximum. Above the Format's cap is honored; null runs at $500; 0 is rejected. Production long-form runs are typically created with caps around $120, a single-scene retry with a few dollars. Details: Spend caps.

What you are charged for is metered generation (video, image, avatar, voice, timeline work) at the rates on the API pricing page. The receipt reports it as usage.billable_amount_usd_micros, which climbs while the run is in flight, counts both reserved and captured amounts, and settles when the run terminates. It excludes the agent's own LLM turn, so it is not the run's total cost, and it is a receipt figure rather than an invoice: GET /v1/usage and GET /v1/balance are the billing records. usage is null when spend could not be read, which is different from 0.

Generation that finished before a cancel or a failure is billed; a later step failing does not refund it. A 4xx at create, an idempotent 200 replay, and a skipped run cost nothing.

Rate limits

Every key has a per-minute request budget across all of /v1, set by the workspace's plan. Reads and writes have separate budgets, and reads get forty times the write number, so polling cannot starve your own creates.

PlanWrites per minuteReads per minute
Free1204800
Pro30012000
Startup60024000
Scale120048000
EnterpriseContracted; Scale until provisionedContracted

A read is any GET: the receipt, status_url, events_url, result_url, Format and run lists. A write is everything else: creating runs and queues, cancel, redeliver.

Every response carries the current state, and a 429 names the budget it came from:

HeaderMeaning
ratelimit-limitRequests allowed in the current window, for the budget this request spent from.
ratelimit-remainingRequests left in that window.
ratelimit-resetSeconds until the window resets.
retry-afterSeconds to wait, sent on 429. error.details.scope is read or write.

Pace on the headers rather than counting requests yourself. Request rate is not generation capacity: how many generations run at once is governed by the plan's concurrency limit, and raising your request rate does not raise it.

Getting help

Every response carries x-sume-request-id, and every receipt carries request_id. Quote them, the run id, and the error.code when you write in. Do not send API keys, signing secrets, or raw media URLs.

Next