moeru-ai/airi · error · TypeError
Audio stream or file is required for streaming transcription
Error message
Audio stream or file is required for streaming transcription.
What it means
A synchronous TypeError thrown by resolveAudioStream when none of options.inputAudioStream, options.inputStream, or options.file is provided to streamTranscription(). The adapter needs exactly one audio source to POST to the transcription endpoint; with no source it cannot form a request body. It fails fast before any network call.
Source
Thrown at packages/stage-ui/src/libs/providers/stream-transcription/index.ts:48
inputAudioStream?: ReadableStream<AudioChunk>
inputStream?: ReadableStream<AudioChunk>
}
function createDeferred<T>() {
let resolve!: (value: T | PromiseLike<T>) => void
let reject!: (reason?: unknown) => void
const promise = new Promise<T>((res, rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
function resolveAudioStream(options: StreamTranscriptionOptions): ReadableStream<AudioChunk> {
const stream = options.inputAudioStream ?? options.inputStream ?? options.file?.stream()
if (!stream)
throw new TypeError('Audio stream or file is required for streaming transcription.')
return stream as ReadableStream<AudioChunk>
}
function parseSSELine(line: string): AIRIStreamTranscriptionDelta | undefined {
if (!line || !line.startsWith('data:'))
return undefined
const content = line.slice('data:'.length)
const data = content.startsWith(' ') ? content.slice(1) : content
if (!data)
return undefined
return JSON.parse(data) as AIRIStreamTranscriptionDelta
}
function createSSETransformer() {
const decoder = new TextDecoder()View on GitHub (pinned to 27111382b4)
Solutions
- Ensure exactly one of inputAudioStream, inputStream, or file is set before calling streamTranscription; pick the most specific source for your caller.
- If using a Blob/File, pass it via options.file and confirm it is non-null.
- Add a caller-side guard that skips transcription when no audio source is available rather than relying on the throw.
- In tests, provide a Blob fixture (e.g. new Blob([bytes], { type: 'audio/wav' })) as options.file.
Example fix
// before
const result = streamTranscription({ baseURL, headers })
// after: pass an explicit source and guard at the call site
if (!micStream && !audioFile)
return
const result = streamTranscription({
baseURL,
headers,
inputAudioStream: micStream ?? undefined,
file: audioFile ?? undefined,
}) Defensive patterns
Strategy: validation
Validate before calling
import type { StreamTranscriptionOptions } from '../stream-transcription'
function hasAudioSource(options: StreamTranscriptionOptions): boolean {
return !!(options.inputAudioStream ?? options.inputStream ?? options.file?.stream())
}
// before calling
if (!hasAudioSource(options)) {
// skip transcription or throw a caller-side error with more context
return
}
const result = streamTranscription(options) Type guard
function isReadableStreamLike(value: unknown): value is ReadableStream {
return typeof value === 'object' && value !== null
&& typeof (value as ReadableStream).getReader === 'function'
}
function resolveAudioSource(options: StreamTranscriptionOptions): ReadableStream | undefined {
if (options.inputAudioStream && isReadableStreamLike(options.inputAudioStream))
return options.inputAudioStream
if (options.inputStream && isReadableStreamLike(options.inputStream))
return options.inputStream
if (options.file && typeof options.file.stream === 'function')
return options.file.stream()
return undefined
} Prevention
- Always pass exactly one of inputAudioStream, inputStream, or file; document which takes precedence in the caller.
- Guard at the call site so the adapter never runs without a source.
- In tests, always provide a Blob fixture as file to avoid this synchronous throw.
When it happens
Trigger: Calling streamTranscription({}) or streamTranscription({ baseURL, headers }) with no audio source; passing options.file as a value whose .stream() is undefined; a code path that constructs options dynamically and forgets to populate one of the three fields.
Common situations: Refactor that renamed inputAudioStream/inputStream and forgot to update a caller; a Hearing module integration where the mic stream is conditionally created and the falsy branch still calls streamTranscription; tests that call the adapter without a fixture file.
Related errors
- Invalid position to break block at.
- Tool input schema must be a JSON Schema object or a Standard
- Streaming transcription request failed with status ${respons
- Streaming transcription response is missing a readable body.
- streaming-tts: not authenticated
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/568da2339001521f.
Report an issue: GitHub.