How to Fix 'timeout error' in LangGraph (TypeScript)
What the error means
A timeout error in LangGraph usually means one of your graph nodes, model calls, or external tool calls took longer than the allowed execution window. In TypeScript projects, it often shows up when a node waits on an LLM request, a retriever, or an API call that never returns before the runtime or client timeout kicks in.
You’ll typically see this during graph.invoke(), graph.stream(), or inside a Runnable wrapped by LangGraph when the underlying promise hangs or exceeds the configured timeout.
The Most Common Cause
The #1 cause is an async node that never resolves fast enough, usually because of an unbounded network call or missing timeout handling around an external dependency.
Here’s the broken pattern:
| Broken | Fixed |
|---|---|
| No timeout on fetch | Explicit timeout with AbortController |
| Node waits forever | Node fails fast and returns a controlled error |
import { StateGraph, START, END } from "@langchain/langgraph";
type State = { input: string; result?: string };
const graph = new StateGraph<State>()
.addNode("callApi", async (state) => {
// Broken: no timeout, can hang indefinitely
const res = await fetch("https://api.example.com/data");
const data = await res.text();
return { result: data };
})
.addEdge(START, "callApi")
.addEdge("callApi", END)
.compile();
await graph.invoke({ input: "hello" });
import { StateGraph, START, END } from "@langchain/langgraph";
type State = { input: string; result?: string };
const graph = new StateGraph<State>()
.addNode("callApi", async (state) => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10_000);
try {
const res = await fetch("https://api.example.com/data", {
signal: controller.signal,
});
if (!res.ok) {
throw new Error(`HTTP ${res.status}: ${res.statusText}`);
}
const data = await res.text();
return { result: data };
} finally {
clearTimeout(timeoutId);
}
})
.addEdge(START, "callApi")
.addEdge("callApi", END)
.compile();
await graph.invoke({ input: "hello" });
If you’re using an LLM node, the same issue applies. A slow model call can surface as something like:
- •
Error: Request timed out - •
TimeoutError: Operation timed out - •
LangGraphError: Node "callModel" exceeded execution time
The fix is the same: set a real timeout at the boundary where the work happens.
Other Possible Causes
1) Recursive graph execution without a stop condition
A cycle in your graph or repeated conditional routing can keep re-entering nodes until the runtime gives up.
// Broken
graph.addConditionalEdges("router", (state) => state.next);
// If state.next keeps returning "router", you loop forever.
// Fixed
graph.addConditionalEdges("router", (state) => {
if (state.steps >= 3) return END;
return state.next;
});
2) Streaming consumer not reading fast enough
If you use graph.stream() and your consumer blocks, backpressure can make it look like a timeout in upstream work.
// Broken
for await (const chunk of graph.stream(input)) {
await slowLogger(chunk); // blocks each iteration
}
// Fixed
for await (const chunk of graph.stream(input)) {
console.log(chunk);
}
// Or buffer and process asynchronously outside the stream loop.
3) Tool call hangs because the tool itself has no deadline
This happens with database queries, HTTP clients, or browser automation tools wrapped inside nodes.
const toolNode = async () => {
// Broken: DB client query with no statement timeout
return await db.query("SELECT * FROM customers");
};
const toolNode = async () => {
await db.query(`SET statement_timeout = '5s'`);
return await db.query("SELECT * FROM customers");
};
For HTTP clients like Axios:
await axios.get(url, { timeout: 5000 });
4) Runtime timeout is lower than your node budget
Sometimes LangGraph is fine; your serverless platform is not. Vercel, Cloudflare Workers, AWS Lambda, and similar runtimes will kill long requests before LangGraph finishes.
// Example: Lambda configured for only 3 seconds.
// Your graph needs ~12 seconds to complete.
await graph.invoke(input);
Fix it by increasing platform limits or moving long-running work out of the request path.
How to Debug It
- •
Find the exact failing node
- •Wrap each node with logging.
- •Log start/end timestamps and state size.
- •If you see
"callModel started"but never"callModel finished", that’s your hotspot.
- •
Check whether it’s LangGraph or the dependency
- •Replace the node body with a stub:
.addNode("callApi", async () => ({ result: "ok" }))- •If the timeout disappears, the bug is in your API/LLM/tool call.
- •
Inspect runtime and client timeouts
- •Check serverless limits.
- •Check reverse proxy timeouts.
- •Check SDK-level timeouts in
fetch, Axios, OpenAI client wrappers, and DB drivers.
- •
Enable structured tracing
- •Use LangSmith if available.
- •Add per-node spans and log durations.
- •Look for nodes that consistently exceed a threshold like
5_000ms.
Prevention
- •
Put a timeout on every external boundary:
- •
fetchwithAbortController - •Axios with
{ timeout } - •DB queries with statement/query deadlines
- •
- •
Keep graphs bounded:
- •Add explicit max-iteration counters
- •Make router conditions deterministic
- •Return
ENDon failure paths
- •
Test under production-like limits:
- •Same runtime as prod
- •Same model provider latency class
- •Same request timeout budget
If you’re seeing LangGraphError, TimeoutError, or plain Request timed out, don’t start by rewriting the graph. Start by finding which node is waiting forever and put a hard deadline on that boundary.
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