# LangGraph multiple interrupts: how to resume each one correctly

By Agent Signal · Published 2026-10-15 · Updated 2026-10-15


Once a graph asks more than one question, resume gets subtle: which `Command(resume=...)` answers which `interrupt()`, and why does the node run four times for three questions? Here is the behavior, run on **langgraph 1.2.15 / langgraph-checkpoint 4.3.0 (Python), Oct 15, 2026**.

## The two rules

- **Several interrupts in one node are matched by position.** The docs: LangGraph "keeps a list of resume values specific to the task executing the node... Matching is strictly index-based, so the order of interrupt calls within the node is important" ([LangGraph interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts)).
- **Interrupts pending at the same time (parallel nodes) are matched by id.** "When resuming multiple interrupts with a single invocation, map each interrupt ID to its resume value."

## Tested example

```python
import operator
from typing import Annotated, TypedDict
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import START, END, StateGraph
from langgraph.types import Command, interrupt

# Part 1: three interrupts in one node, answered one resume at a time
RUNS = {"n": 0}
class Form(TypedDict, total=False):
    name: str; age: int; city: str

def ask(state: Form):
    RUNS["n"] += 1
    name = interrupt("name?"); age = interrupt("age?"); city = interrupt("city?")
    return {"name": name, "age": age, "city": city}

b = StateGraph(Form); b.add_node("ask", ask); b.add_edge(START, "ask"); b.add_edge("ask", END)
g = b.compile(checkpointer=InMemorySaver()); cfg = {"configurable": {"thread_id": "form-1"}}
out = g.invoke({}, cfg); print("pending:", out["__interrupt__"][0].value)
for v in ["Ada", 36, "London"]:
    out = g.invoke(Command(resume=v), cfg)
    print("resumed", repr(v), "->", out["__interrupt__"][0].value if "__interrupt__" in out else out)
print("node executions:", RUNS["n"])

# Part 2: two parallel nodes interrupt in the same step
class S(TypedDict):
    vals: Annotated[list[str], operator.add]
def a(s): return {"vals": [f"a:{interrupt('approve refund?')}"]}
def bb(s): return {"vals": [f"b:{interrupt('approve email?')}"]}
b = StateGraph(S); b.add_node("a", a); b.add_node("b", bb)
b.add_edge(START, "a"); b.add_edge(START, "b"); b.add_edge("a", END); b.add_edge("b", END)
g = b.compile(checkpointer=InMemorySaver()); cfg = {"configurable": {"thread_id": "par-1"}}
out = g.invoke({"vals": []}, cfg)
pending = out["__interrupt__"]; print("pending:", [i.value for i in pending])
out = g.invoke(Command(resume={i.id: ("yes" if "refund" in i.value else "no") for i in pending}), cfg)
print("final:", out)
```

Real output:

```text
pending: name?
resumed 'Ada' -> age?
resumed 36 -> city?
resumed 'London' -> {'name': 'Ada', 'age': 36, 'city': 'London'}
node executions: 4
pending: ['approve email?', 'approve refund?']
final: {'vals': ['a:yes', 'b:no']}
```

Part 1 takes **4 node executions for 3 interrupts**: the node re-runs from the top on every resume and earlier answers are replayed by position. Part 2 answers both parallel interrupts with one `Command(resume={interrupt.id: value})`.

## Mistakes that break it

- **Conditional or non-deterministic interrupts.** Skipping an `interrupt()` behind an `if`, or looping over data that changes between runs, shifts the index and hands answers to the wrong question.
- **`while True` validation loops.** The docs warn each resume "replay[s] all previous iterations." Call `interrupt()` once per node and loop back with a conditional edge instead.
- **Side effects between interrupts.** They re-run on every resume. Keep them in a later node or make them idempotent. See [why a LangGraph interrupt resumes twice](/guides/langgraph-interrupt-resume-twice/).
- **Too many questions?** One `interrupt()` that carries a list keyed by your own ids is often simpler than several calls.

## Tested starters

- Free: [Multiple interrupts in one node](/templates/langgraph-multi-interrupt/), sequential and parallel resume with real run output.
- UI: [Minimal web UI to approve paused runs](/templates/langgraph-approval-ui/).
- Done for you: the [$79 Agent Approval-Flow Fix](/fix/). We repair approval and resume in your LangGraph, OpenAI Agents SDK, Google ADK or Vercel AI SDK agent and deliver a tested patch within 48h, or a full refund. More tested code in [Signal Pro](/pricing/).
