LangGraphLangGraph 1.2 · Python 3.10+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
38 small wins to finish your pathNext lesson →

interrupt: pause for a human

interrupt() pauses a run to ask a person, and Command(resume=value) continues it with their answer. It needs a checkpointer so the paused run can be saved.

Last updated: 27 Sep, 2026 · LangGraph 1.2

Some actions are too costly to leave to a model, such as a refund or a delete. The safe pattern stops, asks a human, and only then goes on.

The interrupt and Command API

python
from langgraph.types import interrupt, Command

def approval(state):
    decision = interrupt("Approve the refund?")   # pauses here
    return {"status": "approved" if decision else "rejected"}

# later, resume with the human's answer:
graph.invoke(Command(resume=True), config)

The example pauses at a refund, waits for a yes, and then finishes. Build it in five small steps.

The imports

python
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt, Command

Two names do the work here: interrupt pauses the run, and Command carries the human's answer back in. InMemorySaver is the checkpointer that saves the paused run.

The state

python
class State(TypedDict):
    status: str        # holds "approved" or "rejected"

The state holds one field, status. It starts empty and ends as the human's decision.

The approval node

python
def approval(state):
    decision = interrupt("Approve the refund?")   # pauses here and asks
    return {"status": "approved" if decision else "rejected"}  # runs after the answer comes back
  • interrupt("Approve the refund?") stops the run at this line and hands the question out to you.
  • When you resume, decision becomes the value you sent back.
  • The node then sets status to "approved" for a truthy answer, else "rejected".

Building the graph

python
builder = StateGraph(State)
builder.add_node("approval", approval)
builder.add_edge(START, "approval")
builder.add_edge("approval", END)
graph = builder.compile(checkpointer=InMemorySaver())  # checkpointer saves the paused run

The graph runs START -> approval -> END. Compiling with a checkpointer is what lets the paused run be saved and picked up again.

Pausing and resuming

python
cfg = {"configurable": {"thread_id": "1"}}
first = graph.invoke({"status": ""}, cfg)        # runs until interrupt, then stops
print("__interrupt__" in first)                  # True: the run paused
final = graph.invoke(Command(resume=True), cfg)  # resume with a yes
print(final["status"])                           # approved
  • The first invoke runs up to interrupt() and stops, returning a result that contains an __interrupt__ marker, so the first print is True.
  • The second invoke sends Command(resume=True), the node continues with decision set to True, and status becomes approved.

Pause and resume end to end

The five steps in one file.

Example
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt, Command

class State(TypedDict):
    status: str

def approval(state):
    decision = interrupt("Approve the refund?")
    return {"status": "approved" if decision else "rejected"}

builder = StateGraph(State)
builder.add_node("approval", approval)
builder.add_edge(START, "approval")
builder.add_edge("approval", END)
graph = builder.compile(checkpointer=InMemorySaver())

cfg = {"configurable": {"thread_id": "1"}}
first = graph.invoke({"status": ""}, cfg)
print("__interrupt__" in first)
final = graph.invoke(Command(resume=True), cfg)
print(final["status"])

Why it paused then approved

  • The first invoke ran until interrupt(), then stopped and returned an __interrupt__ marker instead of finishing.
  • The second invoke passed Command(resume=True), which restarted the node and returned "approved".
  • This only works because the graph was compiled with a checkpointer that saved the paused state.

When to pause for a human

  • Approving anything irreversible: a payment, a delete, an email to a customer.
  • Letting a person edit or correct the agent before it continues.
Watch out. The node re-runs from its first line on resume, so any code above interrupt() runs again. Keep side effects below it, and never wrap interrupt() in a bare try/except.
Try it yourself
  • Resume with Command(resume=False) and read the status.
  • Add a print above interrupt() and count how many times it runs across the two invokes.

Little by little, you're building something great.