mastra-ai/mastra · error · Error

Response body is null

Error message

Response body is null

What it means

Thrown by Run.stream() when the workflow stream request succeeded (response.ok) but response.body is null, so there is no readable stream to pipe through the chunk transform. Indicates an empty or body-less response despite a success status.

Source

Thrown at client-sdks/client-js/src/resources/run.ts:244

      method: 'POST',
      body: {
        inputData: params.inputData,
        initialState: params.initialState,
        requestContext,
        tracingOptions: params.tracingOptions,
        resourceId: params.resourceId,
        perStep: params.perStep,
        closeOnSuspend: params.closeOnSuspend,
      },
      stream: true,
    });

    if (!response.ok) {
      throw new Error(`Failed to stream workflow: ${response.statusText}`);
    }

    if (!response.body) {
      throw new Error('Response body is null');
    }

    // Pipe the response body through the transform stream
    return response.body.pipeThrough(this.createChunkTransformStream());
  }

  /**
   * Observe (reconnect to) an existing workflow stream.
   * Use this to resume receiving events after a disconnection.
   *
   * @param params.offset - Optional position to resume from (0-based). If omitted, replays all events.
   * @returns Promise containing a ReadableStream of workflow events
   *
   * @example
   * ```typescript
   * // Reconnect to a workflow stream from a specific position
   * const stream = await run.observe({ offset: 42 });
   *

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Disable response buffering for streaming endpoints on proxies/gateways.
  2. Confirm server actually emits SSE data for the workflow run (curl -N).
  3. Use a spec-compliant fetch (Node 18+ native fetch) in your environment/tests.
  4. Retry the stream request if transient.

Example fix

// before
const stream = await run.stream({ inputData });
for await (const chunk of stream) { ... }

// after
try {
  const stream = await run.stream({ inputData });
  for await (const chunk of stream) { ... }
} catch (e) {
  if (e.message.includes('Response body is null')) console.error('Empty stream — check proxy/SSE config');
  else throw e;
}
Defensive patterns

Strategy: fallback

Validate before calling

// before streaming, confirm infra supports SSE
const res = await fetch(`${baseUrl}/health`);
if (!res.body) throw new Error('Fetch runtime does not expose response.body');

Type guard

function hasStreamBody(res: Response): res is Response & { body: ReadableStream } { return res.body !== null; }

Try / catch

try {
  const stream = await run.stream({ inputData });
  for await (const chunk of stream) handle(chunk);
} catch (e) {
  if (/Response body is null/.test(e.message)) {
    await pollRunStatus(run); // fallback path
  } else throw e;
}

Prevention

When it happens

Trigger: run.stream() returning 200 but with no body — proxies stripping the SSE payload, server aborting after headers, or a fetch implementation (mock/polyfill) without body support (client-sdks/client-js/src/resources/run.ts:244).

Common situations: Gateway buffering/terminating SSE connections; undici/fetch polyfills in unit tests; server killed mid-response.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/97b486fa802f799d. Report an issue: GitHub.