ValueError: Node 'node_name' not found in graph
langgraph.graph.graph.ValueError (or langgraph.errors.NodeNotFoundError in v0.1.5+)
Stack trace
Traceback (most recent call last):
File "agent.py", line 42, in <module>
graph.add_edge("node_a", "node_b_typo")
File "langgraph/graph/graph.py", line 187, in add_edge
raise ValueError(f"Node 'node_b_typo' not found in graph")
ValueError: Node 'node_b_typo' not found in graph Why it happens
LangGraph StateGraph enforces strict node registration: every node referenced in edges, conditional transitions, or as an END node must be explicitly registered with add_node() first. Common causes are typos in node names (case-sensitive), referencing nodes before they're added, using string node IDs that don't match the registered name, or conditional edges that route to unregistered nodes. The graph validates the DAG at runtime when edges are created or the graph is compiled.
Detection
Enable verbose logging before compiling the graph: set LangGraph's debug mode or manually iterate graph.nodes.keys() to verify all referenced nodes exist. Wrap graph.compile() in a try-except to catch validation errors before running the agent.
Causes & fixes
Typo in node name when adding edges (case-sensitive mismatch)
Check exact spelling and case of node names. Use constants instead of string literals: NODE_NAME = 'check_input'; graph.add_edge(NODE_NAME, 'next_node') to catch typos at definition time.
Conditional edge routes to a node that was never added with add_node()
Before add_conditional_edges(), ensure all target nodes in the condition function are registered. Add missing nodes: graph.add_node('missing_node', missing_node_func)
Using END or START as a node ID when they should be the constants END, START from langgraph.graph.graph
Import and use the constants: from langgraph.graph import START, END; graph.add_edge(START, 'first_node'); graph.add_edge('last_node', END): not string literals.
Adding nodes after edges have been defined or trying to reference a node in a condition before it's registered
Register all nodes first with add_node(), then add edges. Refactor: define all nodes → add all nodes → add all edges → compile.
Code: broken vs fixed
from langgraph.graph import StateGraph, START, END
from langgraph.graph.graph import END as END_CONST
from typing import TypedDict
import anthropic
import os
class AgentState(TypedDict):
messages: list
input: str
def check_input(state: AgentState):
return {'messages': state['messages'] + ['input_checked']}
def process_data(state: AgentState):
return {'messages': state['messages'] + ['processed']}
def route_next(state: AgentState):
if len(state['messages']) > 2:
return 'final_step' # ❌ This node was never added to the graph
return 'process_data'
graph = StateGraph(AgentState)
# ❌ Add nodes — but misspell 'process_data' in the edge
graph.add_node('check_input', check_input)
graph.add_node('process_dat', process_data) # ❌ Typo: 'process_dat' not 'process_data'
graph.add_edge(START, 'check_input')
# ❌ Reference 'process_data' which doesn't exist (registered as 'process_dat')
graph.add_edge('check_input', 'process_data')
# ❌ Conditional edge references 'final_step' which was never added
graph.add_conditional_edges('check_input', route_next, {'process_data': 'process_data', 'final_step': 'final_step'})
# ❌ This will crash with: ValueError: Node 'process_data' not found in graph
compiled_graph = graph.compile() from langgraph.graph import StateGraph, START, END
from typing import TypedDict
import anthropic
import os
class AgentState(TypedDict):
messages: list
input: str
def check_input(state: AgentState):
return {'messages': state['messages'] + ['input_checked']}
def process_data(state: AgentState):
return {'messages': state['messages'] + ['processed']}
def final_step(state: AgentState):
return {'messages': state['messages'] + ['final']}
def route_next(state: AgentState):
if len(state['messages']) > 2:
return 'final_step' # ✅ Now this node exists
return 'process_data'
graph = StateGraph(AgentState)
# ✅ Add ALL nodes with correct names (no typos)
graph.add_node('check_input', check_input)
graph.add_node('process_data', process_data) # ✅ Fixed typo: 'process_data'
graph.add_node('final_step', final_step) # ✅ Added missing node
# ✅ Use START and END constants from imports, not string literals
graph.add_edge(START, 'check_input')
graph.add_edge('check_input', 'process_data')
# ✅ All nodes referenced in conditional edges now exist
graph.add_conditional_edges('check_input', route_next, {
'process_data': 'process_data',
'final_step': 'final_step'
})
graph.add_edge('process_data', END)
graph.add_edge('final_step', END)
# ✅ Graph compiles successfully
compiled_graph = graph.compile()
# Verify the graph
print("Registered nodes:", list(graph.nodes.keys()))
print("Graph compiled successfully!") Workaround
If you can't immediately refactor the graph structure, catch the ValueError during graph construction and print all node names: use a try-except block around graph.compile(), and in the exception handler, print graph.nodes.keys() to see what was actually registered. This reveals typos and missing nodes instantly. Then fix the add_node() calls before re-running.
Prevention
Follow this order: (1) Define all state-processing functions, (2) Create StateGraph, (3) Add ALL nodes with add_node() using a loop or explicit list to avoid typos, (4) Add edges and conditional edges, (5) Compile and test with graph.visualize() (if available) or print graph.nodes and graph.edges to validate structure before deployment. Use Python constants for node names to catch typos at import time.