Stop a Sume Format bulk run mid-batch: cancel starts the next item

The bulk API has no cancel-queue endpoint, and canceling a running child frees its slot for the next item. How to stop a runaway batch, and how to size queues.

5 min readSume
All posts

Canceling one child of a Sume Format bulk run does not stop the batch, because the canceled child frees its slot and the next queued item starts at once. The bulk-runs docs state that the API has no public list-queues or cancel-queue endpoint, so the only cancel is POST /v1/format-runs/{run_id}/cancel on a running child. To stop spend on a large queue you have to plan the size of the queue before you submit it.

What the docs say

A bulk request is a server-side queue of ordinary Format runs with a concurrency window of 1 to 16 and 1 to 100 items. The server keeps concurrency children in flight and starts the next queued item when a slot opens. A completed, failed or canceled child is terminal and frees its slot.

A queued item has run_id null, so there is nothing to cancel by id until it starts. When you cancel a child, the queue marks that item canceled and frees its slot for the next queued item.

What cancel does cost

The cancel call needs formats:write and is idempotent. A canceled response carries cancel_effect, which is canceled when the call stopped a run in progress and no_op when the run had already finished. You pay for the generation the run completed before the cancel, and usage on the receipt shows it. A canceled run never delivers a webhook.

What happens at each point of a bulk run (Sume bulk-runs and runs docs, read 2026-10-08)
SituationEffect
Item is queuedrun_id is null; cannot be canceled by id
Item is runningCancel it with POST /v1/format-runs/{run_id}/cancel
You cancel a running childItem becomes canceled; the next queued item starts
Child already finishedcancel_effect is no_op; receipt returned
Spend before cancelBilled; shown in usage
Queue statuscompleted when every item is terminal; check counts.canceled
curl -sS "https://api.sume.com/v1/format-run-queues/$QUEUE_ID" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  | jq -r '.data.items[] | select(.status=="running") | .run_id' \
  | while read RUN_ID; do
      curl -sS -X POST "https://api.sume.com/v1/format-runs/$RUN_ID/cancel" \
        -H "Authorization: Bearer $SUME_API_KEY" \
        | jq '{id: .data.id, cancel_effect: .data.cancel_effect}'
    done

Plan for stopping before you start

The loop above cancels the children now in flight, but the queue then starts the next items, so you would have to run it again until queued reaches 0. Each pass can start and bill new work, so it is a way to cut a run short, not a clean stop.

The cleaner design is several smaller queues. Submit 100 items as four queues of 25 with the same concurrency, and release the next queue only when the previous one is complete and its counts look right. Stopping then means not submitting the next queue and canceling at most concurrency children.

For a one-off cleanup after a mistake, cancel the running children first, then let the queue drain only if the remaining items are acceptable. If they are not, the queue still holds items you cannot pull, which is the reason to keep queues short.

After the cancel loop, read the queue again. counts.canceled should equal the number of cancels you sent, and the queue status will say completed once every item is terminal, which says nothing about whether the work was wanted.

  • Set generation_spend_cap_usd per item so one child cannot spend more than a known amount.
  • Concurrency 2 to 4 limits how much work starts during a cancel loop.
  • Use a fresh Idempotency-Key per queue; a replayed key returns the old queue.

Sources

Related posts

More in Formats

All Formats posts

Written by Sume