How to Fix 'timeout error' in LangGraph (Python)
A timeout error in LangGraph usually means one of two things: your graph took too long to complete, or one node blocked long enough that the runtime gave up waiting. In practice, this shows up when a tool call hangs, an LLM request exceeds the provider timeout, or your graph has a loop that never reaches a terminal state.
If you’re seeing errors like TimeoutError, asyncio.TimeoutError, or a client-side httpx.ReadTimeout while calling StateGraph.invoke() or CompiledGraph.stream(), the fix is usually in your node logic or timeout settings — not LangGraph itself.
The Most Common Cause
The #1 cause is a node that does blocking work without a timeout, especially when calling an external API, database, or tool from inside a LangGraph node.
Here’s the broken pattern:
| Broken | Fixed |
|---|---|
| No timeout on network call | Explicit timeout on network call |
| Node can hang forever | Node fails fast and returns control |
| Graph waits until runtime kills it | Graph completes or errors predictably |
# BROKEN
import requests
from langgraph.graph import StateGraph, END
def fetch_customer(state):
# Can hang indefinitely if the upstream service stalls
response = requests.get("https://api.example.com/customer/123")
return {"customer": response.json()}
builder = StateGraph(dict)
builder.add_node("fetch_customer", fetch_customer)
builder.set_entry_point("fetch_customer")
builder.add_edge("fetch_customer", END)
graph = builder.compile()
result = graph.invoke({})
The fix is to set timeouts at the call site and handle failures explicitly:
# FIXED
import requests
from langgraph.graph import StateGraph, END
def fetch_customer(state):
try:
response = requests.get(
"https://api.example.com/customer/123",
timeout=10,
)
response.raise_for_status()
return {"customer": response.json()}
except requests.Timeout as e:
return {"error": f"Upstream request timed out: {e}"}
except requests.RequestException as e:
return {"error": f"Upstream request failed: {e}"}
builder = StateGraph(dict)
builder.add_node("fetch_customer", fetch_customer)
builder.set_entry_point("fetch_customer")
builder.add_edge("fetch_customer", END)
graph = builder.compile()
result = graph.invoke({})
If your node calls an LLM, do the same thing there. For example, with an OpenAI client wrapped inside a LangGraph node:
from openai import OpenAI
client = OpenAI(timeout=15.0)
def summarize(state):
resp = client.responses.create(
model="gpt-4.1-mini",
input=state["text"],
)
return {"summary": resp.output_text}
Without a timeout on the downstream client, LangGraph can only wait.
Other Possible Causes
1) Infinite loop in graph routing
A conditional edge that keeps routing back to the same node will look like a timeout if you don’t hit END.
# BROKEN
def route(state):
return "process"
builder.add_conditional_edges("router", route, {
"process": "process",
})
Fix it by adding an exit condition:
# FIXED
def route(state):
if state.get("done"):
return "end"
return "process"
builder.add_conditional_edges("router", route, {
"process": "process",
"end": END,
})
2) Async node not awaited correctly
If you define an async function but call blocking code inside it, the event loop stalls.
# BROKEN
import requests
async def get_data(state):
data = requests.get("https://api.example.com/data").json()
return {"data": data}
Use an async client instead:
# FIXED
import httpx
async def get_data(state):
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get("https://api.example.com/data")
resp.raise_for_status()
return {"data": resp.json()}
3) Provider-side model timeout
Sometimes the issue is not LangGraph at all. The model client throws its own timeout before the graph finishes.
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4.1-mini",
timeout=5, # too low for long prompts / tools / slow regions
)
Increase it and keep retries controlled:
llm = ChatOpenAI(
model="gpt-4.1-mini",
timeout=30,
max_retries=2,
)
4) Large state payloads slowing serialization
If your state contains huge documents, blobs, or full chat histories, every step gets slower.
# BROKEN: storing entire PDFs in state
return {
"documents": [pdf_bytes],
}
Store references instead:
# FIXED: store IDs or file paths
return {
"document_ids": ["doc_123"],
}
How to Debug It
- •
Find the exact exception class
- •Look for
TimeoutError,asyncio.TimeoutError,httpx.ReadTimeout, or provider-specific errors. - •If it’s
httpx.ReadTimeout, the network call timed out. - •If it’s
asyncio.TimeoutError, your coroutine exceeded an async wait limit.
- •Look for
- •
Isolate the slow node
- •Add timing logs around each node.
- •In LangGraph, wrap nodes with simple timing output so you know which step stalls.
import time
def timed_node(fn):
def wrapper(state):
start = time.time()
try:
return fn(state)
finally:
print(f"{fn.__name__} took {time.time() - start:.2f}s")
return wrapper
- •
Check for loops
- •Inspect every conditional edge and verify there is a path to
END. - •If you use recursion or retries inside nodes, make sure they have max attempts.
- •Inspect every conditional edge and verify there is a path to
- •
Test downstream calls outside LangGraph
- •Run the API call directly in a script.
- •If it hangs there too, the problem is external: provider latency, bad DNS, firewall rules, or no timeout setting.
Prevention
- •
Set explicit timeouts on every external dependency:
- •HTTP clients
- •LLM clients
- •database queries
- •tool wrappers
- •
Keep graph state small:
- •store IDs, summaries, and references
- •avoid passing raw files or giant message histories through every node
- •
Add termination guards:
- •max iterations for loops
- •retry caps for transient failures
- •fallback paths to
ENDwhen upstream systems fail
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit