{"record":{"id":"460ab8dc288af50b","repo":"moeru-ai/airi","slug":"streaming-transcription-response-is-missing-a-read","errorCode":null,"errorMessage":"Streaming transcription response is missing a readable body.","messagePattern":"Streaming transcription response is missing a readable body\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/libs/providers/stream-transcription/index.ts","lineNumber":135,"sourceCode":"  })\n\n  void (async () => {\n    try {\n      const requestTarget = options.baseURL instanceof URL\n        ? options.baseURL\n        : new URL(typeof options.baseURL === 'string' ? options.baseURL : 'http://localhost')\n      const response = await fetcher(requestTarget, {\n        body: audioStream,\n        headers: options.headers,\n        method: 'POST',\n        signal: options.abortSignal,\n      })\n\n      if (!response.ok)\n        throw new Error(`Streaming transcription request failed with status ${response.status}`)\n\n      if (!response.body)\n        throw new Error('Streaming transcription response is missing a readable body.')\n\n      await response.body\n        .pipeThrough(createSSETransformer())\n        .pipeTo(new WritableStream<AIRIStreamTranscriptionDelta>({\n          write: (chunk) => {\n            fullStreamCtrl?.enqueue(chunk)\n            if (chunk.type === 'transcript.text.delta') {\n              text += chunk.delta\n              textStreamCtrl?.enqueue(chunk.delta)\n            }\n            else if (chunk.type === 'transcript.text.snapshot') {\n              text = chunk.text\n            }\n          },\n          close: () => {\n            fullStreamCtrl?.close()\n            textStreamCtrl?.close()\n          },","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-ui/src/libs/providers/stream-transcription/index.ts#L117-L153","documentation":"Thrown in streamTranscription's async pump when the transcription POST returns response.ok === true but response.body is null. The adapter must pipe response.body through an SSE transformer to produce transcript deltas; without a body it cannot emit any events and errors both stream controllers plus the text promise.","triggerScenarios":"A 2xx transcription response whose body is not exposed as a ReadableStream: non-streaming fetch polyfill, a proxy that buffers the SSE stream into a single buffered response, or an intermediary that consumed/locked the body before the adapter reads it.","commonSituations":"Running under a fetch shim lacking streaming bodies; a reverse proxy converting Transfer-Encoding: chunked into Content-Length buffered responses; an upstream that returns 200 with empty body on partial failures; Node versions without web streams enabled.","solutions":["Ensure the runtime's fetch exposes streaming bodies on Response (Node 18+ global fetch, modern browsers).","Check proxies/load balancers between client and transcription server do not buffer SSE; they must preserve chunked streaming.","Treat a null body on a 2xx as a transport incompatibility and surface it distinctly from a server error.","Retry once in case of an intermittent upstream empty-body response."],"exampleFix":"// before\nif (!response.body)\n  throw new Error('Streaming transcription response is missing a readable body.')\n\n// after: include status to aid diagnosis\nif (!response.body)\n  throw new Error(\n    `Streaming transcription returned 2xx (status=${response.status}) but no readable body; ` +\n    `verify the transport preserves SSE streaming.`,\n  )","handlingStrategy":"validation","validationCode":"function supportsSSEStreaming(): boolean {\n  return typeof ReadableStream !== 'undefined'\n    && typeof TransformStream !== 'undefined'\n    && typeof globalThis.fetch === 'function'\n}","typeGuard":"function hasStreamingTranscriptionBody(response: Response): response is Response & { body: ReadableStream<Uint8Array> } {\n  return response.ok && response.body instanceof ReadableStream\n}","tryCatchPattern":"const result = streamTranscription(options)\ntry {\n  const text = await result.text\n  // use text\n}\ncatch (error) {\n  if (String(error).includes('no readable body'))\n    reportTransportIncompatibility(error)\n  throw error\n}","preventionTips":["Ensure the runtime and any proxy between client and server preserve chunked SSE streaming.","Treat a missing body on 2xx as a transport/proxy defect and report it separately from server errors."],"tags":["network","streaming","transcription","fetch","transport"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}