mastra-ai/mastra · error

Codex streaming response had no body

Error message

Codex streaming response had no body

What it means

aggregateCodexStream collects a Codex (Responses API) SSE stream into a single text string. It requires the HTTP Response to have a readable body; if response.body is null/undefined it throws 'Codex streaming response had no body', because there is no event stream to aggregate.

Source

Thrown at mastracode/sdk/src/providers/openai-codex.ts:287

}

/**
 * Read an SSE Response and reduce it to a single JSON string matching the
 * non-streaming OpenAI Responses-API shape.
 *
 * Event vocabulary we care about (per OpenAI Responses API streaming):
 *   - response.created         → carries `response` object (id, model, usage stub)
 *   - response.output_item.added/done → output items (message, reasoning, etc.)
 *   - response.output_text.delta → text chunks
 *   - response.completed       → final `response` snapshot incl. usage
 *   - response.error / error   → bubble up as a thrown body
 *
 * Reasoning events (`response.reasoning_summary.*`) are intentionally ignored
 * for the non-streaming text response.
 */
async function aggregateCodexStream(response: Response): Promise<string> {
  if (!response.body) {
    throw new Error('Codex streaming response had no body');
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder('utf-8');
  let buffer = '';

  let finalResponse: any = null;
  let createdResponse: any = null;
  // Track output_items by index so we can rebuild the final array
  const items = new Map<number, any>();
  // Accumulate output_text deltas keyed by item_index + content_index
  const textBuffers = new Map<string, string>();

  const handleEvent = (event: { event?: string; data?: string }) => {
    if (!event.data || event.data === '[DONE]') return;
    let payload: any;
    try {
      payload = JSON.parse(event.data);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check response.ok and status before aggregating; handle auth/rate-limit errors separately.
  2. Ensure the Response passed in is fresh and its body has not been consumed.
  3. Run in an environment that supports streaming response bodies (Node 18+/browsers), not a stripped polyfill.
  4. Inspect the actual HTTP status/headers to see why the server returned no body.

Example fix

// before
const text = await aggregateCodexStream(response); // throws on empty body
// after
if (!response.ok || !response.body) {
  throw new Error(`Codex request failed: ${response.status} (no stream body)`);
}
const text = await aggregateCodexStream(response);
Defensive patterns

Strategy: validation

Validate before calling

if (!response.ok || !response.body) {
  throw new Error(`Codex request failed: ${response.status} (no stream body)`);
}

Type guard

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

Try / catch

try {
  const text = await aggregateCodexStream(response);
} catch (e) {
  if (e.message.includes('no body')) {
    // inspect response.status/headers; surface upstream error to caller
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling aggregateCodexStream with a Response whose body is null — typically a redirect/no-content response, a body already consumed, an error response (e.g. 401/429/5xx) returned without a stream, or a runtime/environment where streaming response bodies are unsupported.

Common situations: Codex auth or rate-limit failure returning an empty non-stream error response; fetch polyfill or edge runtime that doesn't expose response bodies; response body already read elsewhere before aggregation; server returning 204/redirect.

Related errors


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