mastra-ai/mastra · error · APIConnectionError

@mastra/livekit: Mastra agent stream returned an empty respo

Error message

@mastra/livekit: Mastra agent stream returned an empty response body

What it means

The HTTP response from the Mastra agent stream endpoint was ok but had a null/empty body, so there is no SSE stream to read. The library throws APIConnectionError (flagged retryable) because a body-less 200 response cannot yield any reply chunks.

Source

Thrown at integrations/livekit/src/remote.ts:267

              if (cancelled) {
                clearWatchdog();
                break;
              }
              const response = await fetchImpl(url, {
                method: 'POST',
                headers: { 'content-type': 'application/json', accept: 'text/event-stream', ...resolvedHeaders },
                body: JSON.stringify(requestBody),
                signal: abortController.signal,
              });
              if (!response.ok) {
                const errorBody = await safeReadBody(response);
                throw new APIStatusError({
                  message: `@mastra/livekit: Mastra agent stream request failed with status ${response.status}`,
                  options: { statusCode: response.status, body: errorBody, retryable },
                });
              }
              if (!response.body) {
                throw new APIConnectionError({
                  message: '@mastra/livekit: Mastra agent stream returned an empty response body',
                  options: { retryable },
                });
              }

              for await (const chunk of readMastraSSE(
                response.body as unknown as globalThis.ReadableStream<Uint8Array>,
                abortController.signal,
              )) {
                if (cancelled) break;
                // First chunk: the server has committed to this generation — forbid any further
                // retry so the turn can't be replayed mid-stream. The watchdog is NOT cleared here:
                // lifecycle metadata (step-start, text-start, ...) isn't proof the model is
                // producing anything, and disarming on it would turn a post-metadata stall into
                // indefinite dead air. It disarms on the first sign of model output below.
                retryable = false;
                const payload = chunk.payload ?? {};
                switch (chunk.type) {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Retry the request — the error is marked retryable since the failure is transient/transport-level.
  2. Check any proxy/gateway between the worker and the Mastra server for SSE buffering or body stripping (disable buffering, allow streaming responses).
  3. Confirm the Mastra server actually streams SSE for this route (test with curl -N).
  4. Inspect Mastra server middleware that may consume or terminate the response body.

Example fix

// before (nginx)
proxy_buffering on;
// after (nginx)
proxy_buffering off;
proxy_cache off; # allow SSE streaming through to the client
Defensive patterns

Strategy: retry

Try / catch

try {
  await streamReply();
} catch (e) {
  if (e instanceof APIConnectionError && e.message.includes('empty response body')) {
    // transport-level; safe to retry with backoff
    await sleep(backoff(attempt));
    return streamReply();
  }
  throw e;
}

Prevention

When it happens

Trigger: The fetch to /agents/:agentId/stream resolves with response.ok true but response.body null/empty — typically caused by a proxy, gateway, or malformed server response stripping the streaming body.

Common situations: Reverse proxies or load balancers buffering/dropping SSE responses; server closing the connection immediately; middleware consuming the response body before it is returned.

Related errors


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