langgraph "GraphRecursionError: recursion limit of 25 reached" fix
Fixes LangGraph GraphRecursionError when a graph exceeds the default 25-step recursion limit. Use when nodes loop without terminating, when you need to tell a real loop from a legitimately long graph, and when raising the limit safely. Not for exceptions inside a single node or for state-schema validation errors.
TL;DR
GraphRecursionError means your graph ran more than 25 super-steps without finishing, usually because a conditional edge loops forever. Fix the loop by giving it a termination condition, and only raise the limit via config={"recursion_limit": 100} for graphs that are legitimately long.
Error
GraphRecursionError: Graph recursion limit of 25 reached. This can be caused by a loop in your graph, or by simply having too many steps.Steps
- Find the loop. Print the graph and look for conditional edges that point back to an earlier node:
print(app.get_graph().draw_mermaid())Expected output: a diagram of every node and edge. A cycle between two or more nodes is where the loop lives.
- Check whether the loop is supposed to end. Read the conditional edge's decision function and the state field it depends on:
def decide(state):
return "retry" if state["errors"] else "done"Expected output: you can see exactly which state value keeps the loop alive. If the state never moves toward the exit condition, thats the bug.
- Make the loop terminate. Add a counter to the state and bail out after N attempts:
state["attempts"] = state.get("attempts", 0) + 1
if state["attempts"] == 5:
return "done"Expected output: the graph finishes instead of recursing forever, and you get a final state you can inspect.
- If the graph is legitimately long (many sequential steps, no cycle), raise the limit in the invoke config:
result = app.invoke(inputs, config={"recursion_limit": 100})Expected output: the run completes without GraphRecursionError. Set it to roughly 2x your expected step count, not 10000.
When to use
- The graph dies with GraphRecursionError at any limit
- Two or more nodes keep passing control back and forth
- A retry loop (tool calls, self-correction) has no exit counter
When not to use
- A single node raises its own exception (thats the node's code, not the graph loop)
- The error is about the state schema (thats validation, a different fix)
- You want the graph to run forever on a schedule (use an external scheduler, not an unbounded graph)
Variant phrasings
"GraphRecursionError: recursion limit of 50 reached"
Same error, bigger number. Whoever ran it already raised the limit once. Hunt the loop instead of raising it again.
recursion limit hit inside a subgraph
Subgraphs share the parent's step budget. Check the subgraph for the loop first, then the parent edges around it.
Why it happens
LangGraph executes nodes in super-steps and caps them at 25 by default as a safety net against infinite loops. Conditional edges that always return to an earlier node burn through the budget fast. Raising the limit treats the symptom; a termination condition treats the cause.
Edge cases
- A loop that exits on LLM output is fragile: one stubborn model reply restarts the cycle. Always pair it with a hard counter.
- The limit set on
app.invokeapplies per run; streaming withapp.streamneeds the same config passed there too. - Very deep but legitimate pipelines (50+ sequential nodes) trip the default with no loop at all. Thats the one case where raising the limit is the whole fix.
Provenance
Resolved from the public thread: https://vectle.com/posts/pstEShDSqpImjyQACjFYwqCQ