fix(langgraph): add compile-time detection of detached nodes#6751
fix(langgraph): add compile-time detection of detached nodes#6751Saakshi Gupta (saakshigupta2002) wants to merge 3 commits intolangchain-ai:mainfrom
Conversation
This commit introduces optional validation to detect and handle detached nodes (unreachable nodes and dead-end nodes) during graph compilation. Changes: - Add `on_detached_nodes` parameter to `StateGraph.compile()` with three modes: - "warn" (default): Log a warning but compile successfully - "raise": Raise a ValueError and fail compilation - "ignore": Disable detection for dynamic routing scenarios - Add new methods to StateGraph for graph analysis: - `_adjacency`: Build adjacency list from edges, branches, and Command destinations - `_reverse_adjacency`: Reverse adjacency for predecessor lookups - `_nodes_reachable_from_start()`: BFS from START to find reachable nodes - `_unreachable_nodes()`: Find nodes not reachable from START - `_sink_nodes()`: Find nodes with no outgoing edges - `_dead_end_nodes()`: Find sink nodes that aren't END - Add comprehensive test coverage for all scenarios Fixes: langchain-ai#6735
|
It should be enough to check the channels if you wanted |
Hey, thanks for taking a look! :) That's a great point! I hadn't considered using the channels directly for this. Since the branch:to:{node} channels already capture the connectivity after edges and branches are attached, checking which channels have no writers (unreachable) and which nodes don't write to any outgoing channel (dead ends) would be way cleaner than building a separate adjacency list and doing BFS on top of it. I'll rework the implementation to move the detection into the compiled graph stage where the channel info is available. Should keep things a lot simpler and more in line with how the rest of the codebase works. Will push an update soon! |
Rework the detached node detection to leverage the existing compiled
channel/writer infrastructure instead of building a separate adjacency
list with BFS traversal.
Changes:
- Move detection from StateGraph.validate() to
CompiledStateGraph._check_detached_nodes(), which runs after all
attach_node/attach_edge/attach_branch calls when channel info is
fully populated
- Unreachable nodes: check which branch:to:{node} channels have no
writers from ChannelWriteEntry or ChannelWriteTupleEntry.static
- Dead-end nodes: check if a node writes to any branch:to:* channel,
has edges to END in builder.edges, or has conditional branches
- Remove the old _adjacency, _reverse_adjacency, BFS reachability,
_unreachable_nodes, _sink_nodes, _dead_end_nodes methods and their
deque/cached_property imports from StateGraph
- Revert validate() to its original signature (no on_detached_nodes)
The external API (compile(on_detached_nodes=...)) is unchanged.
Pull Request: Compile-time Detection of Detached Nodes
Summary
This PR introduces optional validation to detect and handle detached nodes during graph compilation. Detached nodes are either:
STARTENDThese scenarios often indicate bugs in graph construction that are currently silently ignored, leading to hard-to-debug issues in production.
Changes
New Parameter:
on_detached_nodesAdded a new
on_detached_nodesparameter toStateGraph.compile()with three modes:"warn"(default)"raise"ValueErrorand fail compilation"ignore"Implementation Details
Detection is implemented in
CompiledStateGraph._check_detached_nodes(), which leverages the existing compiled channel/writer infrastructure rather than building a separate graph representation.After
attach_node,attach_edge, andattach_branchpopulate the channel system, the method:ChannelWriteEntryandChannelWriteTupleEntry.staticdeclarationsbranch:to:{name}trigger channel — if not, nothing routes to this nodebranch:to:*channels, explicit edges toENDin the builder, conditional branches, or Command destinations declared instaticThis approach is idiomatic to LangGraph's internal architecture and avoids duplicating connectivity information that the channel system already captures.
Example Usage
Important Notes for Dynamic Routing
For nodes that use
Commandobjects or conditional edges without explicit mappings, the destinations cannot be detected at compile time. In such cases:Use the
destinationsparameter when adding nodes:Or set
on_detached_nodes="ignore"to disable validation.Test Plan
Added comprehensive test coverage for:
goto=ENDBackwards Compatibility
This change is fully backwards compatible:
"warn", which only logs warningsRelated Issue
Fixes: #6735
Files Changed
libs/langgraph/langgraph/graph/state.py_check_detached_nodes()toCompiledStateGraph, addedon_detached_nodesparameter tocompile()libs/langgraph/tests/test_pregel.py