mastra-ai/mastra · error
Response body is null
Error message
Response body is null
What it means
After an ok response from the agent-builder stream endpoint, the client requires a ReadableStream body to pipe through its record parser. A 2xx response with a null body cannot be streamed and triggers this throw.
Source
Thrown at client-sdks/client-js/src/resources/agent-builder.ts:210
const searchParams = new URLSearchParams();
searchParams.set('runId', runId);
const requestContext = parseClientRequestContext(params.requestContext);
const { requestContext: _, ...actionParams } = params;
const url = `/agent-builder/${this.actionId}/stream?${searchParams.toString()}`;
const response: Response = await this.request(url, {
method: 'POST',
body: { ...actionParams, requestContext },
stream: true,
});
if (!response.ok) {
throw new Error(`Failed to stream agent builder action: ${response.statusText}`);
}
if (!response.body) {
throw new Error('Response body is null');
}
return response.body.pipeThrough(this.createRecordParserTransform());
}
/**
* Observes an existing agent builder action run stream.
* Replays cached execution from the beginning, then continues with live stream.
* This is the recommended method for recovery after page refresh/hot reload.
* This calls `/agent-builder/:actionId/observe`
*/
async observeStream(params: { runId: string }): Promise<globalThis.ReadableStream<{ type: string; payload: any }>> {
const searchParams = new URLSearchParams();
searchParams.set('runId', params.runId);
const url = `/agent-builder/${this.actionId}/observe?${searchParams.toString()}`;
const response: Response = await this.request(url, {
method: 'POST',View on GitHub (pinned to 75dd419e61)
Solutions
- Use a runtime with native streaming fetch support (Node 18+, modern browsers).
- Remove interceptors/polyfills that consume the response body.
- In tests, mock with a Response constructed from a real ReadableStream body.
Example fix
// before
mockFetch.mockResolvedValue(new Response(null, { status: 200 }));
// after
mockFetch.mockResolvedValue(new Response(someReadableStream, { status: 200 })); Defensive patterns
Strategy: type-guard
Type guard
function hasBody(res: Response): res is Response & { body: ReadableStream<Uint8Array> } {
return res.body !== null;
} Try / catch
try {
const stream = await agentBuilder.stream(action, runId);
} catch (e) {
if (e instanceof Error && e.message === 'Response body is null') {
// streaming unsupported in this runtime; poll the action status instead
}
throw e;
} Prevention
- Use runtimes with native streaming fetch support.
- Don't intercept/consume the response body before the client reads it.
- In tests, mock responses with real ReadableStream bodies.
When it happens
Trigger: agentBuilder.stream(action, runId) receives an ok response whose body was consumed or never produced — fetch polyfills, response interceptors, or empty 2xx responses from a proxy.
Common situations: Test mocks returning Response without a body; react-native/polyfilled fetch without streaming support; middleware reading response.body before the client.
Related errors
- Response body is null
- Failed to stream background tasks: ${response.statusText}
- A2A ${method} stream response did not include a body (status
- Failed to stream agent builder action: ${response.statusText
- Failed to observe agent builder action stream: ${response.st
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/5f3fb2e4d20a2e2d.
Report an issue: GitHub.