Checked other resources
Related Issues / PRs
Reproduction Steps / Example Code (Python)
import operator
from typing import Annotated
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import START, StateGraph
from langgraph.types import Command, interrupt
from typing_extensions import TypedDict
class State(TypedDict):
answers: Annotated[list[str], operator.add]
def ask_left(state: State) -> State:
return {"answers": [f"left={interrupt('left')}"]}
def ask_right(state: State) -> State:
return {"answers": [f"right={interrupt('right')}"]}
child = (
StateGraph(State)
.add_node("ask_left", ask_left)
.add_node("ask_right", ask_right)
.add_edge(START, "ask_left")
.add_edge(START, "ask_right")
.compile()
)
graph = (
StateGraph(State)
.add_node("child", child)
.add_edge(START, "child")
.compile(checkpointer=InMemorySaver())
)
config = {"configurable": {"thread_id": "nested-parallel-interrupts"}}
first = graph.invoke({"answers": []}, config)
print([(item.id, item.value) for item in first["__interrupt__"]])
# This should raise because two interrupts are pending.
second = graph.invoke(Command(resume="ambiguous"), config)
print(second)
Error Message and Stack Trace (if applicable)
Two different interrupt IDs are initially returned, but no RuntimeError is raised.
The scalar value is delivered to one child branch and the other interrupt remains pending:
{'answers': [], '__interrupt__': [Interrupt(value='right', id='...')]}
Description
PR #6108 intentionally rejects Command(resume=<scalar>) when multiple interrupts are pending because their ordering is nondeterministic. That validation works when each interrupt belongs to a separate top-level task, but it is missed when one parent task wraps a subgraph containing parallel interrupting nodes.
The parent task persists both child interrupts in a single INTERRUPT pending write. PregelLoop._pending_interrupts() currently records only value[0].id for each task, so two child interrupts grouped under one task are counted as one. A scalar resume is then accepted and delivered to one branch according to internal execution order rather than an explicit interrupt ID.
I expected the same RuntimeError used for other multiple-pending-interrupt cases, requiring an interrupt_id -> resume value mapping. This matters for concurrent approval or human-input flows because a scalar response can otherwise be associated with an unintended request.
A narrow fix would collect every interrupt ID in each task's INTERRUPT write while retaining the existing task-level deduplication for resolved writes. I would be happy to submit the fix with sync and async regression coverage if a maintainer approves the approach and assigns this issue to me.
System Info
OS: Darwin (arm64)
Python: 3.13.13
LangGraph: current main at d56666f
langgraph: 1.2.10
langgraph-checkpoint: 4.2.0
langchain-core: 1.5.3
Checked other resources
mainbranch.langchain-communitypackage.Related Issues / PRs
Reproduction Steps / Example Code (Python)
Error Message and Stack Trace (if applicable)
Description
PR #6108 intentionally rejects
Command(resume=<scalar>)when multiple interrupts are pending because their ordering is nondeterministic. That validation works when each interrupt belongs to a separate top-level task, but it is missed when one parent task wraps a subgraph containing parallel interrupting nodes.The parent task persists both child interrupts in a single
INTERRUPTpending write.PregelLoop._pending_interrupts()currently records onlyvalue[0].idfor each task, so two child interrupts grouped under one task are counted as one. A scalar resume is then accepted and delivered to one branch according to internal execution order rather than an explicit interrupt ID.I expected the same
RuntimeErrorused for other multiple-pending-interrupt cases, requiring aninterrupt_id -> resume valuemapping. This matters for concurrent approval or human-input flows because a scalar response can otherwise be associated with an unintended request.A narrow fix would collect every interrupt ID in each task's
INTERRUPTwrite while retaining the existing task-level deduplication for resolved writes. I would be happy to submit the fix with sync and async regression coverage if a maintainer approves the approach and assigns this issue to me.System Info