vercel/ai · error · Error
The response body is empty.
Error message
The response body is empty.
What it means
In HttpChatTransport.reconnectToStream (packages/ai/src/ui/http-chat-transport.ts:265), the reconnect HTTP response returned a 200-ish status but its body is null. The transport needs a readable stream to feed into processResponseStream, so it throws when `response.body` is falsy. This typically means the server/env stripped or failed to produce the body despite an OK status.
Source
Thrown at packages/ai/src/ui/http-chat-transport.ts:265
method: 'GET',
headers,
credentials,
signal: options.abortSignal,
});
// no active stream found, so we do not resume
if (response.status === 204) {
return null;
}
if (!response.ok) {
throw new Error(
(await response.text()) ?? 'Failed to fetch the chat response.',
);
}
if (!response.body) {
throw new Error('The response body is empty.');
}
return this.processResponseStream(response.body);
}
protected abstract processResponseStream(
stream: ReadableStream<Uint8Array<ArrayBufferLike>>,
): ReadableStream<UIMessageChunk>;
}
View on GitHub (pinned to 69428b1f8b)
Solutions
- Fix the server reconnect endpoint so it returns a UI message stream body (e.g. `result.toUIMessageStreamResponse()` from streamText), not an empty 200.
- Check for proxies/middleware that may strip or buffer response bodies on the reconnect route.
- Verify your fetch mock/polyfill in tests provides a real ReadableStream body.
- Wrap reconnect/resume in try-catch and fall back to loading prior messages without streaming when the body is empty.
Example fix
// before (server route)
return new Response(null, { status: 200 });
// after
const result = streamText({ model, messages });
return result.toUIMessageStreamResponse({ originalMessages: messages }); Defensive patterns
Strategy: fallback
Validate before calling
const res = await fetch(reconnectUrl);
if (!res.body) {
// fall back to loading persisted messages instead of streaming
} Type guard
function hasResponseBody(res: Response): res is Response & { body: ReadableStream } {
return res.body != null;
} Try / catch
try {
await chat.reconnectToStream({ chatId });
} catch (e) {
if (e instanceof Error && e.message === 'The response body is empty.') {
await loadPersistedMessages(chatId); // fallback path
} else throw e;
} Prevention
- Return toUIMessageStreamResponse() from reconnect endpoints so a real stream body is present.
- Check proxies/CDNs/middleware for body stripping on streaming routes.
- In tests, always construct Response objects with a ReadableStream body.
- Guard with `if (!response.body)` before resuming streaming and fall back to message loading.
When it happens
Trigger: Calling chat reconnect (useChat resume / Chat.reconnectToStream) where the server responds with an OK status code but the fetch Response has `body === null` (e.g. empty-bodied response, opaque responses, or runtimes like some edge environments returning null bodies).
Common situations: Custom chat route returning 200 without a stream body; reconnect endpoint implemented incorrectly (returns plain `new Response()` or an empty body); proxy/CDN stripping response bodies; unit-test mocks that build a Response without a body.
Related errors
- Incomplete Amazon Bedrock event-stream frame: ${buffer.lengt
- The response body is empty.
- OpenCode event stream ended before the turn settled.
- Failed to reconnect after ${this.maxConsecutiveErrors} conse
- 'element streams in no-schema mode' functionality not suppor
AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30).
Data as JSON: /api/errors/9ba581aa9040b69f.
Report an issue: GitHub.