{"record":{"id":"220be1391b2d48f7","repo":"moeru-ai/airi","slug":"no-audio-tracks-found-in-stream","errorCode":null,"errorMessage":"No audio tracks found in stream","messagePattern":"No audio tracks found in stream","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/composables/audio/audio-recorder.ts","lineNumber":15,"sourceCode":"import type { MaybeRefOrGetter } from 'vue'\n\nimport { until } from '@vueuse/core'\nimport { BufferTarget, MediaStreamAudioTrackSource, Output, QUALITY_MEDIUM, WavOutputFormat } from 'mediabunny'\nimport { computed, ref, shallowRef, toRef } from 'vue'\n\nconst TRANSCRIPTION_WAV_CODEC = 'pcm-s16'\n\n/**\n * Returns the first audio track from the active microphone stream.\n */\nfunction getMediaStreamTrack(stream: MediaStream) {\n  const tracks = stream.getAudioTracks()\n  if (!tracks.length)\n    throw new Error('No audio tracks found in stream')\n  return tracks[0]\n}\n\n/**\n * Records microphone input into short WAV blobs for transcription providers.\n */\nexport function useAudioRecorder(\n  media: MaybeRefOrGetter<MediaStream | undefined>,\n) {\n  const mediaRef = toRef(media)\n  const recording = shallowRef<Blob>()\n\n  const mediaOutput = shallowRef<Output>()\n  const mediaFormat = shallowRef<string>()\n  const isRecording = computed(() => !!mediaOutput.value)\n\n  const onStopRecordHooks = ref<Array<(recording: Blob | undefined) => Promise<void>>>([])\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-ui/src/composables/audio/audio-recorder.ts#L1-L33","documentation":"`getMediaStreamTrack(stream)` reads `stream.getAudioTracks()` and throws `No audio tracks found in stream` when the array is empty. `useAudioRecorder` relies on this to obtain the single track fed into the mediabunny WAV encoder; without a track there is nothing to record.","triggerScenarios":"The `MediaStream` passed to the recorder has no audio tracks — e.g. a stream obtained from `getUserMedia({ video: true })` with no `audio: true`, a display-capture stream with audio disabled, a stream whose audio track was already stopped/removed, or a stream from a device that failed permission.","commonSituations":"Permission denied/revoked mid-session so the audio track was dropped; `getUserMedia` constraints omitting `audio: true`; using a screen-share stream without `audio: true`; the microphone was unplugged after the stream started; browser autoplay policy blocking the track.","solutions":["Request audio explicitly: `getUserMedia({ audio: true })` and check the returned stream has audio tracks before recording.","Guard the recorder start: bail or warn when `stream.getAudioTracks().length === 0`.","Handle permission revocation by re-prompting the user and rebuilding the stream.","Ensure no earlier code called `track.stop()` on the audio track."],"exampleFix":"// before\nconst recorder = useAudioRecorder(stream)\nawait recorder.start()\n\n// after\nif (!stream || stream.getAudioTracks().length === 0)\n  throw new Error('Microphone permission required; no audio track available')\nconst recorder = useAudioRecorder(stream)\nawait recorder.start()","handlingStrategy":"validation","validationCode":"function hasAudioTrack(stream: MediaStream | undefined | null): stream is MediaStream {\n  return !!stream && stream.getAudioTracks().length > 0\n}\n\nif (hasAudioTrack(stream)) useAudioRecorder(stream)","typeGuard":"function streamHasAudio(stream: MediaStream | undefined | null): stream is MediaStream {\n  return !!stream && stream.getAudioTracks().length > 0\n}","tryCatchPattern":"try {\n  useAudioRecorder(stream)\n} catch (e) {\n  if (e instanceof Error && e.message === 'No audio tracks found in stream') {\n    // re-prompt for microphone permission\n  } else throw e\n}","preventionTips":["Request getUserMedia({ audio: true }) and verify audio tracks exist before recording.","Re-acquire the stream after permission/visibility changes.","Avoid calling track.stop() on the audio track mid-session."],"tags":["audio","mediastream","webrtc","permissions"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}