How to Fix 'streaming response cutoff' in LangGraph (TypeScript)
streaming response cutoff in LangGraph usually means the runtime stopped receiving chunks before the stream finished cleanly. In TypeScript, this most often shows up when you’re streaming from an agent or graph node and something in your handler, transport, or model call closes early.
The error is usually not “LangGraph is broken.” It’s typically one of a few integration issues: a thrown exception inside a streamed node, a client disconnect, or a mismatch between async generators and the stream consumer.
The Most Common Cause
The #1 cause is an exception thrown inside a node while LangGraph is streaming updates. The graph starts emitting chunks, then one node fails, and the stream gets cut off before completion.
Here’s the broken pattern:
| Broken | Fixed |
|---|---|
| ```ts | |
| import { StateGraph, START, END } from "@langchain/langgraph"; |
type State = { messages: string[] };
const graph = new StateGraph<State>() .addNode("generate", async (state) => { const last = state.messages[state.messages.length - 1]; // ❌ throws if messages is empty return { messages: [...state.messages, last.toUpperCase()] }; }) .addEdge(START, "generate") .addEdge("generate", END) .compile();
const stream = await graph.stream({ messages: [] }, { streamMode: "values" });
for await (const chunk of stream) {
console.log(chunk);
}
|ts
import { StateGraph, START, END } from "@langchain/langgraph";
type State = { messages: string[] };
const graph = new StateGraph<State>() .addNode("generate", async (state) => { const last = state.messages[state.messages.length - 1]; if (!last) { return { messages: [...state.messages, "fallback message"] }; } return { messages: [...state.messages, last.toUpperCase()] }; }) .addEdge(START, "generate") .addEdge("generate", END) .compile();
const stream = await graph.stream({ messages: [] }, { streamMode: "values" });
for await (const chunk of stream) { console.log(chunk); }
If you’re using `RunnableSequence`, `ChatOpenAI`, or a custom tool inside the node, the same rule applies: any uncaught exception during streaming can surface as:
- `Error: streaming response cutoff`
- `AbortError`
- `GraphExecutionError`
- `LangGraphError`
The fix is to make each streamed node defensive:
- validate inputs before use
- catch tool/model errors inside the node
- return a valid state object even on partial failure
A common production pattern is:
```ts
.addNode("generate", async (state) => {
try {
const result = await model.invoke(state.messages);
return { ...state, messages: [...state.messages, result.content as string] };
} catch (err) {
console.error("generate failed", err);
return { ...state, error: "model_failed" };
}
})
Other Possible Causes
1. Client disconnects during SSE or HTTP streaming
If you’re exposing LangGraph through an API route and the browser closes the connection early, the server sees a cutoff.
// Express / Next.js route example
req.on("close", () => {
controller.abort(); // client disconnected
});
If you abort too aggressively or don’t handle disconnects cleanly, your log may show:
- •
AbortError: The operation was aborted - •
streaming response cutoff
2. Returning non-stream-safe values from a node
LangGraph expects serializable state updates. Returning a class instance, circular object, or raw SDK response can break downstream serialization.
// Bad
return { result: openAIResponse };
// Good
return {
result: openAIResponse.content,
};
If you’re using message objects from LangChain, keep them in the expected schema:
import { AIMessage } from "@langchain/core/messages";
return {
messages: [...state.messages, new AIMessage("done")],
};
3. Mixing sync throws with async generators
A sync error inside an async generator can terminate the stream mid-flight.
async function* badStream() {
yield "chunk1";
throw new Error("boom");
}
Wrap generator logic and emit safe fallback chunks when possible:
async function* safeStream() {
try {
yield "chunk1";
yield "chunk2";
} catch (err) {
yield JSON.stringify({ error: "stream_failed" });
}
}
4. Model/provider timeout or token limit truncation
Some providers stop generating without a clean finish when you hit timeout or context limits.
Check your config:
const model = new ChatOpenAI({
model: "gpt-4o-mini",
temperature: 0,
timeout: 30000,
});
Also watch for max token settings that are too low:
const model = new ChatOpenAI({
maxTokens: 128,
});
If the provider cuts off first, LangGraph only sees an incomplete upstream stream.
How to Debug It
- •
Run without streaming first
- •Replace
graph.stream(...)withgraph.invoke(...). - •If
invoke()fails too, the bug is in your node logic. - •If only streaming fails, look at transport or consumer code.
- •Replace
- •
Add per-node logging
.addNode("generate", async (state) => { console.log("generate input", state); const output = await doWork(state); console.log("generate output", output); return output; })Log before and after every external call:
- •LLM invoke
- •tool execution
- •DB fetch
- •HTTP request
- •
Catch and rethrow with context
try { return await tool.invoke(input); } catch (err) { throw new Error(`tool failed in generate node: ${String(err)}`); }This helps distinguish:
- •provider timeout
- •bad input shape
- •null dereference
- •client abort
- •
Inspect server and client logs together Look for matching timestamps around:
- •
AbortError - •
ECONNRESET - •
streaming response cutoff - •
GraphExecutionError
- •
If you see the server finish normally but the client cuts out early, your issue is likely in:
- •browser fetch handling
- •proxy buffering
- •reverse proxy timeout like Nginx / Cloudflare / Vercel edge limits
Prevention
- •
Validate graph state at every boundary.
- •Don’t assume arrays have elements.
- •Don’t pass raw provider responses through state.
- •
Wrap external calls in try/catch inside nodes.
- •Treat model calls and tools as unreliable dependencies.
- •Return explicit error state instead of letting streams die silently.
- •
Test both
.invoke()and.stream()in CI.- •
.invoke()catches logic bugs. - •
.stream()catches transport and chunking issues.
- •
If you’re still seeing streaming response cutoff, start by isolating which layer is failing:
- •LangGraph node logic
- •LLM/provider call
- •HTTP/SSE transport
- •frontend consumer
That’s how you get from a vague stream failure to one concrete fix.
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