thread_id. That single mechanism is what makes three things possible: inspecting state mid-run, pausing for a human, and resuming exactly where you left off.
What a checkpointer gives you
When you compile a graph with a checkpointer, every superstep writes aCheckpoint to storage. Each checkpoint holds:
channel_values: the materialized state of every channel.next_tasks: the frontier, the[node, arg]pairs that would run next. Persisting the frontier is what lets an interrupted run continue instead of restarting fromSTART.
get_state, update_state, and interrupts all depend on a checkpointer being attached.
Enable checkpointing
Pass a checkpointer tocompile. Use InMemorySaver for development and tests. Then invoke with a thread_id under the configurable key.
Every invocation that shares a
thread_id accumulates on the same thread. A different thread_id starts a fresh, isolated history. If you omit thread_id, the runtime generates a random one, so state cannot be recovered later.checkpoint_ns alongside thread_id to namespace checkpoints within a thread.
Inspect state with get_state
get_state(config) returns a StateSnapshot for the latest checkpoint on the thread.
StateSnapshot is frozen (read-only). Internal channels whose names start with __ are filtered out of values. If the thread has no checkpoint yet, get_state returns an empty snapshot (values={}, next=[]).
Amend state with update_state
update_state(config, values, as_node=None) merges values into the persisted state and writes a new checkpoint. Use it to correct or inject state before resuming a paused run.
channel_values, and the resulting checkpoint is tagged with source="update". update_state returns the thread config pointing at the new checkpoint.
Pause before or after a node
Declare interrupt points at compile time.interrupt_before pauses the run just before any listed node is about to execute; interrupt_after pauses once a listed node has run.
GraphInterrupt. Catch it, review the state, then decide whether to continue.
Interrupts require a checkpointer. The pause is implemented by persisting the frontier, so a graph compiled without one cannot pause and resume.
Interrupt from inside a node
For a pause that depends on runtime data, raiseNodeInterrupt inside the node itself. The runtime catches it, checkpoints the current frontier, and surfaces it as a GraphInterrupt carrying your value.
NodeInterrupt is a subclass of GraphInterrupt, so a single except GraphInterrupt handler catches both static interrupt points and in-node interrupts.
Resume by re-invoking
To continue a paused run, callinvoke (or ainvoke) again with the same thread_id. The runtime restores the channels and the saved frontier, and it does not re-trigger the interrupt that paused it. The run picks up from the frontier and drains to completion.
1
Run until it pauses
The first
invoke raises GraphInterrupt and persists a checkpoint with the pending frontier.2
Inspect or amend (optional)
Call
get_state to see what runs next, and update_state to inject a human decision.3
Resume
Re-invoke with the same
config. Execution continues from the saved frontier.await app.ainvoke(...) and async for step in app.astream(...) restore and persist state identically.
Bound runaway loops with recursion_limit
Cyclic graphs (an agent that loops between a model and its tools) need a stop condition. recursion_limit caps the number of supersteps and raises GraphRecursionError instead of looping forever. The default is 25.
GraphRecursionError is a subclass of Python’s built-in RecursionError, and it carries .limit and .current so you can report how far the run got.
Custom checkpoint backends
InMemorySaver is for development and testing; its storage is lost when the process exits. For durable persistence, implement BaseCheckpointSaver against your own backend. The key methods are:
Compile with your saver in place of
InMemorySaver, and everything above (get_state, update_state, interrupts, resume) works unchanged.
Where to go next
Checkpointing gives you the plumbing for a human to approve or edit a run in the moment. When you need approvals that survive process restarts and can resume hours later, and a tamper-evident record of what was decided, the governance layer builds on this same substrate.Governance
Deny-by-default policy, risk tiering, and durable human approval on the agent loop.
StateGraph
Nodes, edges, reducers, and the superstep runtime that checkpointing sits on.