Skip to main content
← Back to list
01Issue
BugShippedSwamp CLIPublic
Assigneeshammz

Relationships

#2430 workflow resume: Ctrl-C leaves the run 'running' with nothing driving it, and it can no longer be resumed

Opened by hammz · 9/23/2026· Shipped 9/23/2026

Problem

Pressing Ctrl-C during swamp workflow resume exits the process with code 130 but leaves the run record at running. The step that was executing and its dependents stay pending, and the run tracker row stays running. Nothing is driving the run, and it cannot be resumed again: resume --run <id> and resume --from <step> --run <id> both refuse a running run.

This affects every local resume: a suspended run after approval, --from on a failed run, and the retry of a failed run added by swamp-club#2409. The retry makes it easier to hit, since every failed run now prints a swamp workflow resume <wf> --run <id> command to run next.

A fresh swamp workflow run handles the same Ctrl-C: it records the run as cancelled and exits 1.

The only way out today is swamp workflow cancel <wf> --run <id>, which moves the run to cancelled. A cancelled run cannot be retried or resumed with --from, so the steps that already succeeded are lost and the operator has to start a new run.

Cause

workflow run suppresses the datastore sync coordinator's Deno.exit(130) on SIGINT (suppressSyncExitOnSignal()), and when its abort signal fires it saves the run as cancelled before exiting. workflow resume (src/cli/commands/workflow_resume.ts) registers a shutdown handler that aborts its controller, but it does not suppress that exit, so the process exits before resume() can save anything. It also has no fallback that saves a terminal status for the run after an abort.

Expected

Ctrl-C during a resume leaves the run in a terminal state, and the tracker row agrees with it. workflow run uses cancelled. For a resume, consider whether an operator interrupt should leave the run retryable (for example failed, with the interrupted step recorded), because cancelled discards a run the operator explicitly chose to continue.

Fix approach

Give the local resume path the same SIGINT handling as workflow run: keep the process alive after SIGINT, let resume() unwind on the abort signal, save the chosen terminal status if the generator did not, and complete the tracker row before exiting non-zero. Check the remote path (resume --server) separately.

Reproduction (Linux)

  1. Create a workflow with a step s that runs sleep 6; test -f /tmp/repro/ok and a step t that depends on s.
  2. swamp workflow run slow: s fails. Note the run id.
  3. touch /tmp/repro/ok, then swamp workflow resume slow --run <id> (or --from s --run <id>, or approve a suspended run and swamp workflow resume <wf>).
  4. Press Ctrl-C while s is running. The process exits 130.
  5. swamp workflow history get slow --json: status running, s and t pending. swamp run history --active still lists the run as running.
  6. swamp workflow resume slow --run <id> refuses: Run <id> is not suspended or failed (status: running).

Reproduced on main at c811f8ce for the --from and post-approval resumes, and on the swamp-club#2409 branch for all three.

Related: swamp-club#2420 (a resume keeps the original run's process identity, so workflow cancel cannot stop a live resume).

02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 25 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

9/23/2026, 11:10:29 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
hammz assigned hammz9/23/2026, 8:00:53 PM

Sign in to post a ripple.