409 previous_run_not_terminal: continue a Format run after it ends
Continuing a Format run with previous_run_id while the first is still running returns 409. Wait for terminal, then continue; a failed create frees its key.

409 previous_run_not_terminal means the run named in previous_run_id has not finished. A continuation replays what the first run produced, so it can only start once that run is terminal. Wait for it, then send the same continuation again. Nothing ran and nothing was charged for the refused call, and a failed create releases its Idempotency-Key, so you may reuse the key you chose.
What are the four refusals on previous_run_id?
Continuing a run is how an integration retries one scene without paying for the whole run again. The call is refused four ways, and each has a different next step.
| Status and code | Means | Next step |
|---|---|---|
| 404 previous_run_not_found | Unknown id, or another owner's run | Check the id and the key |
| 400 previous_run_format_mismatch | That run was created on a different Format | Continue it on the Format it started on |
| 409 previous_run_not_terminal | It has not finished | Poll it, then call again |
| 400 previous_run_not_resumable | Nothing to continue; details has previous_run_status, has_thread, artifact_count | Start a fresh run |
Which previous runs can be continued?
You can read it off the earlier receipt: thread_id is not null, and the run either completed or has a non-empty artifacts[]. A failed run that left work behind can be continued, and one that left nothing cannot. A continuation is a new run with a new id, its own spend cap and its own single webhook. The original never changes.
Two traps follow. Continue by naming previous_run_id, never by sending a thread id, which is 400 unknown_parameter. And bind the same output_schema on every turn: it is per run, not inherited.
Wait, then continue
waitForRun resolves for any terminal status, so it is the right gate. Then subscribeFormatRun creates the continuation. Use a new key for the continuation, since the first run's key is bound to its own receipt.
import { subscribeFormatRun, waitForRun } from "@sume-com/sdk";
export async function retryScene(client, previousRunId: string, sceneId: string) {
const prev = await waitForRun(previousRunId, { client, family: "format" });
if (prev.status === "canceled" || prev.status === "skipped") {
throw new Error(`cannot continue a ${prev.status} run`);
}
return subscribeFormatRun({
client,
path: { handle: "acme", slug: "live-commerce" },
idempotencyKey: `${previousRunId}-retry-${sceneId}`,
body: {
previous_run_id: previousRunId,
instruction: "Retry the selected scene only. Keep every other scene.",
input: { scene_id: sceneId },
generation_spend_cap_usd: 8,
},
});
}What if I want overlapping runs instead?
That is a different control. on_active_run: "reject" returns 409 format_run_in_progress when a run is already in flight on that Format, and the cause is concurrency on the Format rather than a dependency between two runs. Do not confuse the two 409s: one is solved by waiting for a specific earlier run, the other by dropping reject or waiting for any run.
What does a continuation cost and return?
A continuation is billed as its own run against its own spend cap, so set generation_spend_cap_usd for the single scene you are redoing, not for the whole show. Generation that finished on the first run is on the thread and is not regenerated, which is what makes the retry cheap. artifacts[] on the continued run is the place to confirm what the second turn actually produced.
If the first run failed with incomplete_assembly or agent_reported_failure, continuing it is the recommended recovery, because the finished clips are real. Starting a fresh run with a new key would pay for them again.
Where do I read the first run's state?
The receipt of the earlier run is the source of truth: GET /v1/format-runs/{run_id} returns it at any status, with thread_id, status, artifacts[] and previous_run_id if it was itself a continuation. Read it before you build the continuation request, and you can tell the 409 case (still running) from the 400 case (finished with nothing to continue) without sending the call at all.
Sources
Related posts
More in Developers
- studio_agent_upstream_unavailable 503: retry, the run keeps going
A Sume 503 studio_agent_upstream_unavailable is a Sume-side outage: retry create with the same Idempotency-Key, and keep polling a run you already hold.
- GET format-runs result 409 run_not_completed: poll status first
Reading result_url while a Format run is in flight returns 409 run_not_completed with details.status. Poll status_url, then read the receipt once terminal.
- Format run webhook_delivery status: what each value means
A Format run receipt carries webhook_delivery with six statuses: not_armed, pending, retrying, delivered, failed, exhausted. Read them to decide on a redeliver.
- frame_images needs frame_type: first_frame or last_frame on Sume
Each frame_images entry on POST /v1/videos needs a frame_type. What the two values mean, how supported_frame_images limits them, and a pre-check.
Written by Sume