Manual cancellation

Stop a running workflow execution from the CLI, REST API, or Python SDK — and understand what happens to in-flight tasks when the signal lands.

Cancelling a workflow tells the runtime to stop its execution cleanly. The worker receives the signal, cancels the asyncio task running the workflow, and writes a final CANCELLED state to the execution record. This page covers the three surfaces you use to send that signal: the CLI, the REST API, and the Python SDK.

What happens when you cancel

Cancellation is cooperative. When the server receives a cancel request it:

  1. Transitions the execution to CANCELLING state and persists the change.
  2. Notifies the worker holding the execution via SSE.
  3. The worker calls .cancel() on the asyncio task running the workflow.
  4. Python delivers asyncio.CancelledError at the next await inside the workflow or its tasks.
  5. The @workflow decorator catches the error, calls ctx.cancel(), and the execution reaches CANCELLED.

The execution record is immutable after that point. Tasks that completed before the signal was delivered keep their recorded outputs; in-flight tasks do not retry.

Cancel from the CLI

flux workflow cancel <workflow-name> <execution-id>

Both arguments are required. <workflow-name> is the registered name of the workflow; <execution-id> is the UUID returned when the execution was started.

flux workflow cancel data_pipeline exec-abc-123

The command returns immediately; it does not wait for the worker to finish unwinding. To confirm the execution reached a terminal state, poll flux execution show <execution-id> until the status is CANCELLED, COMPLETED, or FAILED. If your server is not on localhost:8000, pass --server-url:

flux workflow cancel data_pipeline exec-abc-123 --server-url http://my-server:8000

The CLI accepts one optional flag:

FlagDefaultDescription
--server-urlhttp://localhost:8000Flux server to connect to.

Cancel via the REST API

The cancel endpoint follows the same pattern as other execution-scoped routes:

GET /workflows/{namespace}/{workflow_name}/cancel/{execution_id}

The HTTP method is GET. Query parameters:

ParameterDefaultDescription
modeasyncasync returns immediately; sync blocks until the execution is terminal.
detailedfalseReturn the full execution context rather than a summary.

Example with curl:

curl -X GET \
  "http://localhost:8000/workflows/default/data_pipeline/cancel/exec-abc-123?mode=async" \
  -H "Authorization: Bearer <api-key>"

A 200 response with mode=async means the cancel request was accepted and queued. The execution may still be CANCELLING for a moment while the worker unwinds. Poll GET /executions/{execution_id} or use mode=sync to wait for the terminal state.

If the execution has already finished, the server returns 400 with "Cannot cancel a finished execution." Cancellation is a no-op on completed, failed, or already-cancelled executions.

Cancel from the Python SDK

FluxClient exposes cancel_execution as an async method:

import asyncio
from flux.client import FluxClient


async def main():
    async with FluxClient("http://localhost:8000") as client:
        result = await client.cancel_execution(
            workflow_ref="default/data_pipeline",
            execution_id="exec-abc-123",
        )
        print(result)


asyncio.run(main())

workflow_ref uses the "namespace/name" format. The method maps to the same REST endpoint as the curl example above.

cancel_execution returns the execution summary dict on success:

{
    "execution_id": "exec-abc-123",
    "state": "CANCELLING",   # or "CANCELLED" if the worker finished immediately
    ...
}

To confirm the execution reached CANCELLED rather than stopping at CANCELLING, either poll client.get_execution(execution_id) or use a mode=sync workaround by calling the REST endpoint directly via the underlying httpx client.

Checking the result

After sending the cancel request, retrieve the final state:

# CLI — inspect a single execution by ID
flux execution show exec-abc-123 --detailed

# REST
curl "http://localhost:8000/executions/exec-abc-123" -H "Authorization: Bearer <api-key>"

(flux workflow show <name> takes only the workflow name plus an optional --version; it doesn’t accept an execution ID. Use flux execution show for execution-level details.)

The state field will be one of:

StateMeaning
CANCELLINGSignal delivered; worker still unwinding.
CANCELLEDTerminal. Execution stopped cleanly.
COMPLETEDExecution finished before the signal landed.
FAILEDExecution failed (independently of the cancel request).