moeru-ai/airi · error · Error
Streaming transcription response is missing a readable body.
Error message
Streaming transcription response is missing a readable body.
What it means
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.
Source
Thrown at packages/stage-ui/src/libs/providers/stream-transcription/index.ts:135
})
void (async () => {
try {
const requestTarget = options.baseURL instanceof URL
? options.baseURL
: new URL(typeof options.baseURL === 'string' ? options.baseURL : 'http://localhost')
const response = await fetcher(requestTarget, {
body: audioStream,
headers: options.headers,
method: 'POST',
signal: options.abortSignal,
})
if (!response.ok)
throw new Error(`Streaming transcription request failed with status ${response.status}`)
if (!response.body)
throw new Error('Streaming transcription response is missing a readable body.')
await response.body
.pipeThrough(createSSETransformer())
.pipeTo(new WritableStream<AIRIStreamTranscriptionDelta>({
write: (chunk) => {
fullStreamCtrl?.enqueue(chunk)
if (chunk.type === 'transcript.text.delta') {
text += chunk.delta
textStreamCtrl?.enqueue(chunk.delta)
}
else if (chunk.type === 'transcript.text.snapshot') {
text = chunk.text
}
},
close: () => {
fullStreamCtrl?.close()
textStreamCtrl?.close()
},View on GitHub (pinned to 27111382b4)
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.
Example fix
// before
if (!response.body)
throw new Error('Streaming transcription response is missing a readable body.')
// after: include status to aid diagnosis
if (!response.body)
throw new Error(
`Streaming transcription returned 2xx (status=${response.status}) but no readable body; ` +
`verify the transport preserves SSE streaming.`,
) Defensive patterns
Strategy: validation
Validate before calling
function supportsSSEStreaming(): boolean {
return typeof ReadableStream !== 'undefined'
&& typeof TransformStream !== 'undefined'
&& typeof globalThis.fetch === 'function'
} Type guard
function hasStreamingTranscriptionBody(response: Response): response is Response & { body: ReadableStream<Uint8Array> } {
return response.ok && response.body instanceof ReadableStream
} Try / catch
const result = streamTranscription(options)
try {
const text = await result.text
// use text
}
catch (error) {
if (String(error).includes('no readable body'))
reportTransportIncompatibility(error)
throw error
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- OpenRouter audio response has no body
- Streaming transcription request failed with status ${respons
- Failed to fetch image: ${response.statusText}
- Failed to fetch MMD model: ${response.status} ${response.sta
- OpenRouter audio request failed: ${response.status} ${await
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/460ab8dc288af50b.
Report an issue: GitHub.