How to Fix 'timeout error in production' in LangGraph (TypeScript)
If you’re seeing timeout error in production in LangGraph, it usually means one of your graph steps is taking longer than the platform, proxy, or serverless runtime allows. In practice, this shows up when an LLM call, tool call, or long-running branch blocks the graph until the request times out.
In TypeScript projects, the root cause is usually not LangGraph itself. It’s almost always a bad execution pattern: no streaming, no timeout control, no checkpointing, or a node that does too much work synchronously.
The Most Common Cause
The #1 cause is a node that waits on a slow external call without any timeout handling or partial progress. In production, that often means your Runnable or graph node hangs until your API gateway returns 504 Gateway Timeout.
Here’s the broken pattern:
import { StateGraph } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({ model: "gpt-4o" });
const graph = new StateGraph<{ input: string; output?: string }>()
.addNode("generate", async (state) => {
// Broken: no timeout, no retry, no fallback
const res = await llm.invoke(state.input);
return { output: res.content as string };
})
.addEdge("__start__", "generate")
.addEdge("generate", "__end__")
.compile();
await graph.invoke({ input: "Summarize this policy" });
And here’s the fixed pattern:
import { StateGraph } from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
const llm = new ChatOpenAI({
model: "gpt-4o",
timeout: 20_000,
});
async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ms);
try {
return await promise;
} finally {
clearTimeout(timer);
}
}
const graph = new StateGraph<{ input: string; output?: string }>()
.addNode("generate", async (state) => {
const res = await withTimeout(
llm.invoke(state.input),
20_000
);
return { output: res.content as string };
})
.addEdge("__start__", "generate")
.addEdge("generate", "__end__")
.compile();
await graph.invoke({ input: "Summarize this policy" });
The key difference is simple:
| Broken | Fixed |
|---|---|
Unbounded await llm.invoke(...) | Explicit timeout on model call |
| One slow step blocks the whole request | Request fails fast and predictably |
| No visibility into latency | Easier to trace and retry |
If you’re using LangGraph in a web API, also make sure your HTTP server timeout is longer than your longest expected graph run. A common failure looks like this:
- •
Error: Request timed out - •
504 Gateway Timeout - •
GraphRecursionErrorafter retries keep restarting the same slow branch
Other Possible Causes
1) Recursive loops in the graph
A bad conditional edge can keep sending execution back into the same node until you hit a recursion limit or runtime timeout.
// Broken
graph.addConditionalEdges("router", (state) => "router");
// Fixed
graph.addConditionalEdges("router", (state) =>
state.needsMoreWork ? "worker" : "__end__"
);
If you see GraphRecursionError, this is often the culprit.
2) Tool calls that block too long
External APIs are a common source of production timeouts.
// Broken
.addNode("lookup", async () => {
const data = await fetch("https://slow-vendor.example.com/data");
return { data: await data.json() };
});
// Fixed
.addNode("lookup", async () => {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 10_000);
try {
const data = await fetch("https://slow-vendor.example.com/data", {
signal: controller.signal,
});
return { data: await data.json() };
} finally {
clearTimeout(timer);
}
});
3) No checkpointing on multi-step graphs
Without persistence, retries can restart expensive work from scratch.
import { MemorySaver } from "@langchain/langgraph";
// Better for dev only; use durable storage in prod
const checkpointer = new MemorySaver();
If your deployment restarts mid-run, you’ll see repeated execution and eventual timeout. In production, use a durable checkpointer backed by Redis, Postgres, or another persistent store.
4) Large prompts or giant state objects
Passing huge state through every node increases serialization and latency.
// Broken
return {
documents: allDocs,
transcript: hugeTranscript,
};
// Fixed
return {
documentIds: allDocs.map((d) => d.id),
};
Keep state minimal. Store large payloads outside the graph and pass references instead.
How to Debug It
- •
Find the exact failing node
- •Add logging inside each node.
- •Log start/end timestamps.
- •The slowest node is usually where the timeout starts.
- •
Check whether it’s LangGraph or infrastructure
- •If you see
504 Gateway Timeout, look at your reverse proxy, load balancer, or serverless limits. - •If you see
GraphRecursionError, inspect loops and conditional edges. - •If you see an OpenAI/Anthropic SDK timeout message, it’s probably the model call itself.
- •If you see
- •
Run the graph step-by-step
- •Execute individual nodes outside the full graph.
- •Confirm whether one tool call or prompt is consistently slow.
- •Reduce inputs until latency drops.
- •
Measure external dependencies
- •Time every
fetch, DB query, and LLM call. - •If one dependency crosses your budget repeatedly, add caching, batching, or a shorter fallback path.
- •Time every
A simple timing wrapper helps:
async function timed<T>(name: string, fn: () => Promise<T>) {
const start = Date.now();
try {
return await fn();
} finally {
console.log(`${name} took ${Date.now() - start}ms`);
}
}
Prevention
- •Put hard timeouts on every LLM call and external request.
- •Keep graph state small; don’t move large documents through every node.
- •Use checkpointing in production so retries don’t restart expensive work.
- •Set explicit budgets per node:
const NODE_TIMEOUT_MS = {
router: 2_000,
lookup: 10_000,
generate: 20_000,
};
If you treat LangGraph like a synchronous monolith, production will punish you with timeouts. Build each node like a bounded operation with clear failure modes, and these errors become rare instead of recurring.
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