TellWorldAI World Archive
Ask中文

Home›Practice›Practice

Practice

Interrupts in LangGraph: pause for human input

Use interrupt() to pause a LangGraph node, save state and wait for human input, then resume with Command; includes an approval example and the rules that follow from re-running nodes.

Who this is for and what you will be able to do

This guide is for developers building LangGraph workflows that must stop at a certain step and wait for a person to confirm or supply information. After reading it, you can call interrupt() inside a node, understand how state is saved and resumed, send the person's answer back with Command, and follow the rules that come from re-running nodes.

What an interrupt is

An interrupt pauses graph execution at a point you choose and waits for external input before continuing. This is the basis of human-in-the-loop work, such as asking a person to approve an API call, a database change or a financial transaction.[1]

When an interrupt fires, LangGraph saves the graph state through its persistence layer and waits indefinitely until you resume execution. You trigger it by calling the interrupt() function in a node. It accepts any JSON-serializable value and hands that value to the caller.[1]

Interrupts differ from static breakpoints, which pause only before or after particular nodes. An interrupt is dynamic: it can sit anywhere in your code and can depend on application logic.[1]

Prerequisites

  • Persistence: interrupts need a checkpointer to save state. Use a durable checkpointer in production; an in-memory one is enough for tests and prototypes.[1]
  • Thread ID: pass thread_id in the config. The checkpointer uses it to load the right state. A new value starts a brand-new thread with empty state.[1]
  • Data: values given to interrupt() must be JSON-serializable.[1]

Pause, wait and resume

The minimal approval node below calls interrupt with a question. Execution pauses at that point, and the question is the value the caller receives. On resume, the value in Command(resume=...) becomes the return value of that interrupt() call, and the node continues.[1]

from langgraph.types import interrupt

def approval_node(state: State):
    # Pause and ask for approval
    approved = interrupt("Do you approve this action?")

    # When you resume, Command(resume=...) returns that value here
    return {"approved": approved}

Three points matter on resume. You must use the same thread ID as the run that paused. The resume value is what interrupt() returns. The node restarts from its beginning, so any code before the interrupt() call runs again.[1]

In Python, the page recommends driving the graph with event streaming, graph.stream_events(..., version="v3"). Interrupt values then appear on stream.interrupts, and stream.interrupted is True when the run is waiting for input. The default invoke() surfaces them under result["__interrupt__"] instead.[1]

An approval example

Approval is the most common use. The node below hands a question and details to a person, then routes with Command(goto=...) to "proceed" or "cancel" based on the answer:

from typing import Literal
from langgraph.types import interrupt, Command

def approval_node(state: State) -> Command[Literal["proceed", "cancel"]]:
    # Pause execution; payload shows up on stream.interrupts (with stream_events) or result["__interrupt__"] (with invoke)
    is_approved = interrupt({
        "question": "Do you want to proceed with this action?",
        "details": state["action_details"]
    })

    # Route based on the response
    if is_approved:
        return Command(goto="proceed")  # Runs after the resume payload is provided
    else:
        return Command(goto="cancel")

To approve, resume with Command(resume=True). To reject, use Command(resume=False). Both use the same config:

# To approve
graph.stream_events(Command(resume=True), config=config, version="v3").output

# To reject
graph.stream_events(Command(resume=False), config=config, version="v3").output

Note that Command(resume=...) is the only Command pattern meant as input to invoke(), stream() or stream_events(). To continue a multi-turn conversation, pass a plain input dict, not Command(update=...).[1]

Response schemas and several interrupts

The response_schema argument to interrupt describes the input expected on resume, which lets clients render typed forms. It requires langgraph 1.2.12 or later.[1] A Pydantic model, a TypedDict from typing_extensions, or a dataclass can validate resume values. LangGraph converts the type to JSON Schema and places it in Interrupt.response_schema, separate from the value.[1]

When parallel branches interrupt together, resume them in one call by mapping each interrupt ID to its resume value.[1] The common patterns include approval workflows, handling multiple interrupts, reviewing and editing state, interrupting tool calls, and validating human input.[1]

Rules that follow from re-running nodes

Interrupts are implemented by raising a special exception, which the runtime catches to save state and wait. On resume, the runtime re-executes the node from its start, not from the line that called interrupt().[1] Several rules follow.

**Do not wrap interrupt in try/except.** The special exception would be caught and the interrupt would never reach the graph. Keep interrupt calls separate from error-prone code.[1]

Do not reorder interrupts within a node. Resume values are matched strictly by index, so the order of calls matters.[1]

Pass simple values. Some checkpointers cannot serialize complex objects such as functions, so pass JSON-serializable types.[1]

Make side effects before an interrupt idempotent. The node runs again on resume, so writes or API calls placed before interrupt should be safe to repeat. Move side effects after the interrupt where you can.[1]

Subgraphs and debugging

When a subgraph is invoked as a function inside a node, the parent resumes from the start of the node that invoked it, and the subgraph resumes from the start of the node where its interrupt was called.[1]

For debugging, set interrupt_before and interrupt_after when compiling the graph. They act as static breakpoints, so you can step through one node at a time.[1]

Limits and common questions

  • Without a checkpointer and a thread ID, interrupted state cannot be resumed.[1]
  • Resuming with a different thread ID starts a new empty thread, so the paused state is not continued.[1]
  • Code before interrupt runs again on resume, so check that it is safe to re-run.[1]
  • Values that cannot be serialized may fail with some checkpointers.[1]

Next steps

To learn how to validate human input or review and edit state, read the interrupts chapters in the LangGraph documentation. The same documentation also covers subgraphs and streaming.[1]

Adapted from the LangChain documentation page *Interrupts* (LangGraph section)[1], released under the MIT License.

Sources

  1. 1
    InterruptsLangChain docs (MIT)

Cite this page: Interrupts in LangGraph: pause for human input. TellWorld, https://www.tellworld.net/practice/practice-langgraph-interrupts. Updated 2026-11-14

Related news

View all