Cancel a video chain midway: 409 job_generation_already_started

Cancel works only before generation starts. In a render, trim and captions chain, cancel queued jobs, let started jobs finish, and stop submitting steps.

4 min readSume
All posts

You cannot cancel a Sume job that has already started generating. POST /v1/jobs/:id/cancel succeeds only before generation work starts; after that it returns 409 job_generation_already_started with details.cancelable: false, and the job runs to completion. For a chain of render, trim and captions, stopping midway therefore means three things: cancel jobs that are still queued, let started jobs finish, and do not submit the next step.

What cancel does for each step

The chain is three separate jobs, so cancel is decided per job. The one that matters is the job that is active when you decide to stop.

Cancel result by chain state (read 2026-10-05)
Where the chain isCancel callOutcome
Render queued, not startedCancel the render jobJob becomes canceled
Render startedCancel the render job409 job_generation_already_started; it completes or fails normally
Render done, trim not yet submittedNothing to cancelDo not submit the trim
Trim queuedCancel the trim jobJob becomes canceled
Job already canceledCancel againIdempotent: returns the same canceled job

The call

The cancel request needs no body and no idempotency header, because a repeat on a canceled job is harmless.

curl -X POST https://api.sume.com/v1/jobs/job_123/cancel \
  -H "Authorization: Bearer $SUME_API_KEY"

Stopping a chain in your own code

Keep a stopped flag next to your stored job ids. When it is set, the step runner checks it before every submit, and it never creates the next job. Then, for the job in flight, send cancel and read the response. A 200 means canceled. A 409 with job_generation_already_started is not a failure of your stop: keep polling status_url until terminal is true, and treat the output as optional.

The admission docs say to cancel queued jobs you no longer need before they start processing. That also frees accepted capacity, which matters when queue_full is blocking other submissions. A job that has started cannot give its capacity back early.

Events help when you are unsure what state a job reached. GET /v1/jobs/:id/events lists job.created, job.queued, job.started, generation.submitted and the terminal events, so you can see whether job.started appears before you decide the cancel was too late.

What a canceled job does to the chain

A canceled job is terminal. Its status reads canceled, and the result read returns 409 job_not_completed because there is no result. Your chain code should treat canceled like failed for the purpose of the next step: there is no input, so do not submit. It should also fire the webhook path you built for job.canceled, if you listen for it.

Cancel does not refund work that already ran, and the docs only say that cancel succeeds before generation starts. Read the job's credit line from the status or result, not from an assumption, before you tell a user that nothing was spent.

Repeated stop requests from a UI are safe. A second cancel on a canceled job returns the same canceled job.

  • canceled is terminal.
  • No result exists, so no next step.
  • Repeat cancels are idempotent.

Deciding whether to cancel at all

Cancel is not always the right stop. If the render has started, the credits for that work are committed to the job's run, and the useful move is often to let it finish and use or discard the output. Cancel pays off for queued jobs, especially when a wave of work was submitted by mistake or when queue_full is blocking something more important.

Make the choice explicit in your tooling: show the job state, show whether job.started has appeared in the events, and offer cancel only when it can succeed. A button that always ends in a 409 teaches people to ignore errors.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume