moeru-ai/airi · error · Error
No microphone stream available for voice input
Error message
No microphone stream available for voice input
What it means
`startAutoSegmentation` reads `mediaRef.value` (the microphone `MediaStream`) and throws `No microphone stream available for voice input` when it is falsy. The VAD-based segmentation and the volume fallback both require a live stream to attach analyser/source nodes.
Source
Thrown at packages/stage-ui/src/composables/audio/voice-input-session.ts:565
}
}
volumeFallbackAnimationFrame = requestAnimationFrame(analyze)
}
volumeFallbackAnimationFrame = requestAnimationFrame(analyze)
}
catch (error) {
stopVolumeFallback()
lastError.value = error
log('error', 'volume-fallback-start-failed', 'Failed to start volume-based recorder fallback.', { error })
}
}
async function startAutoSegmentation() {
const stream = mediaRef.value
if (!stream)
throw new Error('No microphone stream available for voice input')
await startVoiceInputVadDetectionSafely({
init: initVAD,
loaded: () => vadLoaded.value,
start: startVAD,
stream,
getError: () => vadError.value,
log,
})
await startVolumeFallback(stream)
}
async function stop(options: { flushActiveRecording?: boolean } = {}) {
stopVolumeFallback()
disposeVAD()
transcriptionChain.reset()
stoppedRecordingSegments.length = 0
vadRecordings.clear()View on GitHub (pinned to 27111382b4)
Solutions
- Ensure the microphone stream is acquired (`getUserMedia({ audio: true })`) and assigned to `mediaRef` before starting segmentation.
- Gate the start button on a truthy stream (`watch(mediaRef, ...)` or `until(mediaRef).not.toBeNull()`).
- Re-acquire the stream on permission/visibility change before restarting.
- Surface a user-facing 'microphone not ready' state instead of throwing.
Example fix
// before
startAutoSegmentation() // mediaRef.value is undefined -> throws
// after
const stream = mediaRef.value
if (!stream) {
lastError.value = new Error('Microphone is not ready. Grant permission and try again.')
return
}
await startAutoSegmentation() Defensive patterns
Strategy: validation
Validate before calling
if (!mediaRef.value) {
lastError.value = new Error('Microphone is not ready. Grant permission and try again.')
return
}
await startAutoSegmentation() Type guard
function hasMicrophoneStream(ref: { value: MediaStream | undefined }): boolean {
return !!ref.value && ref.value.getAudioTracks().length > 0
} Try / catch
try {
await startAutoSegmentation()
} catch (e) {
if (e instanceof Error && e.message === 'No microphone stream available for voice input') {
// acquire stream, then retry
} else throw e
} Prevention
- Acquire the microphone stream before exposing the start-listening action.
- Gate the start button on a truthy mediaRef with audio tracks.
- Re-acquire the stream on permission/visibility change.
When it happens
Trigger: Starting auto voice segmentation before `mediaRef` has been populated (e.g. before `getUserMedia` resolved, after the stream was stopped/revoked, or when the parent never assigned a stream). The check is a synchronous read of the ref's current value.
Common situations: Calling `startAutoSegmentation` before microphone permission was granted; the stream was cleared on tab visibility change or device change; race where the UI 'start listening' action fires before the stream composable emits; ref not wired to the actual `MediaStream`.
Related errors
- No audio tracks found in stream
- Selected source did not provide a live video track
- Permission denied: ${details.area}.${details.action} "${deta
- Cannot declare permissions for unknown plugin "${extensionId
- Cannot grant permissions to unknown plugin "${extensionId}".
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/2cf374c22551ce4d.
Report an issue: GitHub.