moeru-ai/airi · warning

1. Microphone permission not granted - browser should prompt

Error message

1. Microphone permission not granted - browser should prompt automatically

What it means

This is line 2 of the same multi-line diagnostic `console.warn` block in `streamWebSpeechAPITranscription`, emitted when the Web Speech recognition did not start immediately. This line specifically names missing microphone permission as the most likely cause, noting that the browser should prompt the user automatically. It is informational output, not a thrown error; a hard permission failure is separately surfaced as 'Microphone permission denied.'

Source

Thrown at packages/provider-inference/src/providers/local/browser-web-speech-api/provider.ts:458

  recognition.onsoundend = () => {
    console.info('Web Speech API sound ended')
  }

  recognition.onaudioend = () => {
    console.info('Web Speech API audio capture ended')
  }

  recognition.onnomatch = () => {
    console.info('Web Speech API: No speech match')
  }

  const started = startRecognition()
  if (!started) {
    // If immediate start failed, it might be a permission issue
    // Web Speech API will prompt for permission automatically, so we just log
    console.warn('Web Speech API recognition did not start immediately. This might be due to:')
    console.warn('1. Microphone permission not granted - browser should prompt automatically')
    console.warn('2. Recognition already running - this is normal if called multiple times')
    console.warn('3. Browser requires user gesture - ensure microphone was enabled by user action')

    // Don't retry immediately - wait for permission or user action
    // The recognition instance is already created, so it can be started later if needed
  }

  return {
    fullStream,
    text: deferredText.promise,
    textStream,
    recognition: recognitionInstance,
  }
}

View on GitHub (pinned to f679616c34)

Solutions

  1. Ensure the call originates from a user gesture so the browser can show the mic permission prompt.
  2. Check `navigator.permissions.query({ name: 'microphone' })`; if 'denied', instruct the user to re-enable the mic in site settings.
  3. In Electron/Capacitor, pre-grant or request microphone permission through the platform API before starting transcription.
  4. Listen for the recognizer's 'not-allowed' error, which the provider converts into a hard 'Microphone permission denied.' stream error.

Example fix

// before
startListening() // page load, no gesture — prompt never shows

// after
micButton.onclick = async () => {
  await navigator.mediaDevices.getUserMedia({ audio: true }) // triggers prompt inside gesture
  startListening()
}
Defensive patterns

Strategy: validation

Validate before calling

const perm = await navigator.permissions.query({ name: 'microphone' })
if (perm.state !== 'granted') {
  // must be called from a user gesture to surface the prompt
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
  stream.getTracks().forEach(t => t.stop())
}

Type guard

function hasMicPermission(state: PermissionState): state is 'granted' { return state === 'granted' }

Try / catch

try {
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
  stream.getTracks().forEach(t => t.stop())
  await startTranscription()
} catch (error) {
  if (error instanceof DOMException && error.name === 'NotAllowedError') {
    showMicPermissionInstructions()
  }
}

Prevention

When it happens

Trigger: Same as the parent warning: `startRecognition()` returned false because `recognition.start()` failed, with ungranted microphone permission being the leading suspect — e.g. the user has not yet answered the mic permission prompt or previously denied it.

Common situations: First-time use of voice input before granting mic access; permission previously blocked in browser site settings; embedded WebView (Electron/Capacitor) without mic permission pre-granted; calling before any user gesture so the prompt cannot appear.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@f679616c34 (2026-09-08). Data as JSON: /api/errors/9a74daa95d38ebc0. Report an issue: GitHub.