{"record":{"id":"bf0cf282e4744425","repo":"mastra-ai/mastra","slug":"codex-streaming-response-had-no-body","errorCode":null,"errorMessage":"Codex streaming response had no body","messagePattern":"Codex streaming response had no body","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/sdk/src/providers/openai-codex.ts","lineNumber":287,"sourceCode":"}\n\n/**\n * Read an SSE Response and reduce it to a single JSON string matching the\n * non-streaming OpenAI Responses-API shape.\n *\n * Event vocabulary we care about (per OpenAI Responses API streaming):\n *   - response.created         → carries `response` object (id, model, usage stub)\n *   - response.output_item.added/done → output items (message, reasoning, etc.)\n *   - response.output_text.delta → text chunks\n *   - response.completed       → final `response` snapshot incl. usage\n *   - response.error / error   → bubble up as a thrown body\n *\n * Reasoning events (`response.reasoning_summary.*`) are intentionally ignored\n * for the non-streaming text response.\n */\nasync function aggregateCodexStream(response: Response): Promise<string> {\n  if (!response.body) {\n    throw new Error('Codex streaming response had no body');\n  }\n\n  const reader = response.body.getReader();\n  const decoder = new TextDecoder('utf-8');\n  let buffer = '';\n\n  let finalResponse: any = null;\n  let createdResponse: any = null;\n  // Track output_items by index so we can rebuild the final array\n  const items = new Map<number, any>();\n  // Accumulate output_text deltas keyed by item_index + content_index\n  const textBuffers = new Map<string, string>();\n\n  const handleEvent = (event: { event?: string; data?: string }) => {\n    if (!event.data || event.data === '[DONE]') return;\n    let payload: any;\n    try {\n      payload = JSON.parse(event.data);","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/sdk/src/providers/openai-codex.ts#L269-L305","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check response.ok and status before aggregating; handle auth/rate-limit errors separately.","Ensure the Response passed in is fresh and its body has not been consumed.","Run in an environment that supports streaming response bodies (Node 18+/browsers), not a stripped polyfill.","Inspect the actual HTTP status/headers to see why the server returned no body."],"exampleFix":"// before\nconst text = await aggregateCodexStream(response); // throws on empty body\n// after\nif (!response.ok || !response.body) {\n  throw new Error(`Codex request failed: ${response.status} (no stream body)`);\n}\nconst text = await aggregateCodexStream(response);","handlingStrategy":"validation","validationCode":"if (!response.ok || !response.body) {\n  throw new Error(`Codex request failed: ${response.status} (no stream body)`);\n}","typeGuard":"function isStreamable(res: Response): res is Response & { body: ReadableStream } {\n  return res.body != null;\n}","tryCatchPattern":"try {\n  const text = await aggregateCodexStream(response);\n} catch (e) {\n  if (e.message.includes('no body')) {\n    // inspect response.status/headers; surface upstream error to caller\n  }\n  throw e;\n}","preventionTips":["Always check response.ok/status before consuming a stream.","Never read response.body before passing the Response to the aggregator.","Run on runtimes with full streaming Response support (Node 18+, browsers)."],"tags":["streaming","network","openai-codex","response-body"],"backgroundTag":"empty-response-body","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}