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

Relationships

#2899 workflow approve on a run that is not suspended prints a fatal error with a stack trace

Opened by hammz · 10/1/2026· Shipped 10/2/2026

Description

swamp workflow approve on a run that is not suspended (for example a run that failed because a parallel gate was rejected) exits 1 with an [FTL] log line and a full JavaScript stack trace, rather than the short user-facing error other workflow commands give in the same situation (resume prints Error: Run <id> is not suspended or failed (status: …)).

Steps to reproduce

Repro workflow (workflows/workflow-e2e-wf.yaml; each step appends to a log so real executions can be counted):

id: <uuid>
name: e2e-wf
version: 1
concurrency: 1
jobs:
  - name: a-side
    steps:
      - name: gate2
        task: { type: manual_approval, prompt: "gate2?" }
      - name: s
        dependsOn: [{ step: gate2, condition: { type: succeeded } }]
        task: { type: model_method, modelType: command/shell, modelName: m-s, methodName: execute,
                inputs: { run: "echo s >> /tmp/exec.log; sleep 3" } }
  - name: main
    steps:
      - name: gate
        task: { type: manual_approval, prompt: "gate?" }
      - name: post
        dependsOn: [{ step: gate, condition: { type: succeeded } }]
        task: { type: model_method, modelType: command/shell, modelName: m-post, methodName: execute,
                inputs: { run: "echo post >> /tmp/exec.log" } }
  - name: teardown
    dependsOn: [{ job: main, condition: { type: always } }]
    steps:
      - name: t
        task: { type: model_method, modelType: command/shell, modelName: m-t, methodName: execute,
                inputs: { run: "echo t >> /tmp/exec.log" } }
  1. swamp workflow run e2e-wf (suspends at gate2 and gate).
  2. swamp workflow reject e2e-wf gate2 --run <id>. The run becomes failed, and main stays running with gate waiting_approval.
  3. swamp workflow approve e2e-wf gate --run <id>.

Actual

[FTL] error: Error: Run <id> is not suspended (status: failed)
    at error (file:///…/src/cli/commands/workflow_approve.ts:165:17)
    at consumeStream (file:///…/src/libswamp/stream.ts:57:11)
    at async Command.<anonymous> (file:///…/src/cli/commands/workflow_approve.ts:145:5)
    at async Command.execute (https://jsr.io/@cliffy/command/1.0.1/command.ts:2307:7)
    …

Expected

A one-line user error with no stack trace, ideally with the next step, e.g. Error: Run <id> is not suspended (status: failed). Use 'swamp workflow resume e2e-wf --run <id> --from <step>' to re-enter it. --json mode returns a structured error.

Environment: Linux x86_64. Reproduced with release 20260930.225800.0-sha.1a9b497f and with the swamp-club#2597 branch (e337ad45), so it is not a regression from that fix. Found while end-to-end validating swamp-club#2597.

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

Shipped

10/2/2026, 10:00:12 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
hammz assigned hammz10/2/2026, 9:05:37 PM
Editable. Press Enter to edit.

hammz commented 10/1/2026, 7:55:34 PM

More evidence from end-to-end validation of swamp-club#2895:

  • workflow reject has the same problem. It throws a plain Error at src/cli/commands/workflow_reject.ts:158. Approve does the same at src/cli/commands/workflow_approve.ts:131 and :173 (throw new Error(e.error.message)).
  • A cancelled run hits it too, not only a failed one. Approving or rejecting a gate on a run that workflow cancel already cancelled triggers it.
  • --json mode leaks the stack into the structured error on stderr. Compare workflow resume, which returns only {"error": "..."}:
    {
      "error": "Run <id> is not suspended (status: cancelled)",
      "stack": "    at error (file:///…/src/cli/commands/workflow_approve.ts:173:17)\n    at consumeStream (…/src/libswamp/stream.ts:57:11)\n …"
    }

Reproduced with release 20261001.190402.0-sha.543aad7e and with branch 8ae02e19.

Sign in to post a ripple.