Skip to course content
Free LangGraph course

LangGraph for Agentic Workflows

Unit 08.03: Cancelling a run cleanly

Cancellation in a graph is cooperative. Nothing interrupts a node that is already running, so the check has to be somewhere the graph will reach.

Check at the top of every node, before any effect

A cancelled flag in the state, read at the start of each node. A cancelled node returns without acting and the run drains to its end cleanly.

The code cancels between two steps and shows what runs afterwards.

from typing import TypedDict


class State(TypedDict):
    cancelled: bool
    charged: bool
    log: list


def checkpointed_step(state: State, name, effect=None):
    """Check for cancellation at the top of every node, before any effect."""
    if state["cancelled"]:
        return {"log": state["log"] + [f"{name}: skipped, run cancelled"]}
    if effect:
        effect()
    return {"log": state["log"] + [f"{name}: done"]}


s = {"cancelled": False, "charged": False, "log": []}
s = {**s, **checkpointed_step(s, "prepare")}
s = {**s, "cancelled": True}                      # user pressed cancel here
s = {**s, **checkpointed_step(s, "charge", effect=lambda: None)}
s = {**s, **checkpointed_step(s, "notify")}

for line in s["log"]:
    print(" ", line)
print(f"\ncharged: {s['charged']}")

# Cancellation is cooperative: nothing interrupts a running node, so the check
# sits at the top of each one. A cancel that kills the process instead leaves
# the state half-written and the external system half-updated.

prepare completed before the cancel; charge and notify both skipped, and charged stayed false. The run ended in a consistent state that records what happened and what did not.

The alternative - killing the process - leaves the state half-written and, worse, may leave an external system half-updated, with no record of which. A cooperative cancel is slower to take effect and leaves something you can reason about.

The mistake this prevents

The mistake is putting the cancellation check after the effect, or in the router rather than in the node. A router-level check skips the node's *routing* while the node itself has already run. The check belongs at the top of the node body, before anything outward happens.

Takeaway

Cancellation is a state flag checked at the top of every node, before any side effect. Killing the process instead leaves both your state and the external system in an unknown condition.