Last Updated: 3/11/2026
Error Handling
Common LangGraph errors and how to fix them.
Graph Recursion Limit
Error:
GraphRecursionError: Recursion limit of 25 reachedCause: Your graph executed more than the maximum allowed steps (default 25).
Solutions:
-
Increase the limit (if your workflow is legitimately long):
app.invoke(inputs, config={"recursion_limit": 100}) -
Fix infinite loops (if your graph is looping unintentionally):
- Check conditional edges for logic errors
- Ensure nodes eventually route to END
- Add counters to break loops:
def route(state): if state["attempts"] > 10: return END return "retry_node"
Missing Checkpointer
Error:
CheckpointerRequired: This operation requires a checkpointerCause: You’re using interrupt(), get_state(), or update_state() without a checkpointer.
Solution: Compile with a checkpointer:
from langgraph.checkpoint.memory import MemorySaver
app = builder.compile(checkpointer=MemorySaver())Invalid Graph Node Return Value
Error:
InvalidUpdateError: Node returned invalid typeCause: Node returned something other than a dict/object with state updates.
Solution: Always return a dict/object:
# Bad
def my_node(state):
return "hello" # Wrong!
# Good
def my_node(state):
return {"message": "hello"}Invalid Concurrent Graph Update
Error:
InvalidUpdateError: Multiple nodes tried to update the same channelCause: Parallel nodes both updated the same state key without a reducer.
Solution: Add a reducer for that key:
from typing import Annotated
import operator
class State(TypedDict):
# This key can be updated by parallel nodes
items: Annotated[list, operator.add]Invalid Chat History
Error:
ValueError: Message list must alternate between human and AICause: Your message list doesn’t follow the expected format.
Solution: Ensure proper message alternation:
messages = [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi there"},
{"role": "user", "content": "How are you?"},
]Multiple Subgraphs
Error:
MultipleSubgraphsError: Cannot use multiple subgraphs in one nodeCause: You added more than one subgraph to a single node.
Solution: Use separate nodes for each subgraph:
# Bad
builder.add_node("combined", [subgraph1, subgraph2])
# Good
builder.add_node("subgraph1", subgraph1)
builder.add_node("subgraph2", subgraph2)Common Mistakes
Forgetting to Compile
# Bad - forgot to compile
builder = StateGraph(State)
builder.add_node("node", my_node)
builder.invoke(inputs) # Error!
# Good
app = builder.compile()
app.invoke(inputs)Missing thread_id
# Bad - no thread_id with checkpointer
app = builder.compile(checkpointer=MemorySaver())
app.invoke(inputs) # Error!
# Good
config = {"configurable": {"thread_id": "1"}}
app.invoke(inputs, config)Not Connecting Nodes
# Bad - orphaned node
builder.add_node("node_a", node_a)
builder.add_node("node_b", node_b) # Never reached!
builder.add_edge(START, "node_a")
builder.add_edge("node_a", END)
# Good
builder.add_edge("node_a", "node_b")
builder.add_edge("node_b", END)Debugging Tips
Use Debug Mode
for chunk in app.stream(inputs, stream_mode="debug"):
print(chunk)Check State at Each Step
for chunk in app.stream(inputs, stream_mode="values"):
print(f"State: {chunk}")Inspect State History
config = {"configurable": {"thread_id": "1"}}
app.invoke(inputs, config)
for snapshot in app.get_state_history(config):
print(f"Step {snapshot.metadata['step']}: {snapshot.values}")Enable LangSmith Tracing
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY=your-keyThen view traces at https://smith.langchain.com
Best Practices
- Always compile: Don’t invoke on the builder
- Use checkpointers in production: MemorySaver is for development only
- Set recursion limits appropriately: Balance safety and flexibility
- Add error handling in nodes: Catch and handle expected errors
- Test edge cases: Empty state, missing fields, parallel updates
Next Steps
- Graph API Reference: Complete API documentation
- Building Graphs: Practical patterns and examples