Format run incomplete_assembly: continue it, do not pay twice
incomplete_assembly means the run hit its time limit with generation jobs unfinished. Read pending_job_count, then continue with previous_run_id.

The short answer
A Format run that fails with incomplete_assembly reached its time limit before all of its generation jobs finished. The media you got back is not all the media the run paid for. Do not start a fresh run. Continue the failed run with previous_run_id: the finished clips are already on the thread, and the continuation does not generate them again.
That is the whole recovery path in Sume's documentation as of 2026-10-08. The rest of this page is how to read the failure, and what to send on the continuation so it stays cheap.
What the receipt tells you
A failed run still carries its artifacts. For incomplete_assembly the error details name the unfinished work, so you can decide whether continuing is worth it before you spend anything.
| Field | What it holds | What to do with it |
|---|---|---|
| error.code | incomplete_assembly | Branch on this code, not on the message text. |
| error.details.pending_job_count | How many generation jobs had not finished | Log it. A count of 1 is a different story from 12. |
| error.details.pending_jobs[] | The unfinished jobs by name | Use them to tell the continuation which part is missing. |
| artifacts[] | Every durable file the run did make | Keep these URLs. They are real, and they stay. |
| output | The partial ledger, when your schema permits it | Read output_error before you trust it. |
| primary_output_url | null on any failure | Test this field to know if the deliverable exists. |
Continue, with a new key
A continuation is a new run with its own id, its own receipt, its own spend cap and its own single webhook. The original receipt never changes. Both runs share thread_id.
Send a new Idempotency-Key. The old key is bound to the receipt you already have, and the docs say to retry a failed run with a new key. Bind the same output_schema again, because the schema is per run and is not inherited.
Name the previous run, not the thread. A thread id in the body returns 400 unknown_parameter.
curl -sS -X POST "https://api.sume.com/v1/formats/acme/live-commerce/runs" \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-8823-lc-v1-finish-1" \
-d '{
"previous_run_id": "arun_e43e6c5cb2b74052",
"instruction": "Finish only the clips that did not complete. Keep every finished clip.",
"output_schema": { "name": "acme/live-commerce/v1", "schema": { "type": "object", "additionalProperties": false, "required": ["full_video"], "properties": { "full_video": { "$ref": "SumeMediaFile#" } } } },
"primary_output_key": "full_video",
"generation_spend_cap_usd": 8
}'When you cannot continue
The run you name must be continuable: its thread_id is not null, and it either completed or has a non-empty artifacts[]. A failed run that left work qualifies. Four refusals exist: 404 previous_run_not_found, 400 previous_run_format_mismatch, 409 previous_run_not_terminal, and 400 previous_run_not_resumable.
If you are inside a bulk queue, the item shows only the generic format_run_failed. Read the child receipt at GET /v1/format-runs/{run_id} to see the real code before you retry anything.
- Spend on the original run is not refunded for generation that already finished.
- The continuation has its own cap. The docs describe a single-scene retry as needing a fraction of a full-run cap, so size it to the missing work.
- Webhook consumers get a second
format.run.terminalevent with the new run id, not a repeat of the first.
Deciding before you spend
The time limit is a platform bound, not something you set. A non-terminal receipt carries expires_at: the deadline after which Sume force-finalizes the run as failed. It is 90 minutes from created_at, or earlier when the run is older than 25 minutes and has been silent for 10. Long-form video is often 15 to 30 minutes of work, so a run that reaches this limit usually means a stuck or very large job, not a slow one.
Read GET /v1/format-runs/{run_id}/events on the failed run. It is a phase timeline (preparing, running, finalizing), not a log. If the at clock on the last entry stopped moving for several minutes, the run stalled. A continuation then has a good chance of finishing what the first run could not, because it starts a new turn on the same thread.
If pending_job_count is large compared with the number of artifacts, ask whether the brief asked for too much in one turn. Splitting a long brief into two runs, each with its own cap, keeps one stall from holding every clip.
- Continue when artifacts exist and the missing part is a minority of the work.
- Start a new run when
artifacts[]is empty andprevious_run_not_resumablewould be the answer anyway. - Never reuse the failed run's
Idempotency-Key; derive a new one from your item id plus a retry counter.
Sources
Related posts
More in Formats
- Format run mcp_unavailable: failed before the model, charged false
mcp_unavailable means the per-turn tools never attached, so the run stopped before any turn. details.charged is false. Retry with a new Idempotency-Key.
- output_extraction_failed: harvest_unavailable or harvest_threw?
output_extraction_failed has two reasons with opposite handling: reread a completed run, or report a host defect. Here is how to tell them apart.
- primary_output_missing: your schema passed but the key is empty
A Format run can satisfy your output_schema and still fail because primary_output_key is empty. Here is how to read it and fill the gap.
- provider_credits_exhausted: why a Format run says retryable false
This Format run error is on Sume's side, not your balance or input. details.retryable is false, so do not re-fire in a loop. Here is the handling.
Written by Sume