moeru-ai/airi · warning

Web Speech API recognition start failed:

Error message

Web Speech API recognition start failed:

What it means

startRecognition()'s initial recognition.start() threw synchronously. The handler classifies the message: 'already started' is treated as OK (returns true), 'not-allowed'/'permission' fails the stream with a permission error, and anything else triggers the new-instance retry. Typical exceptions are InvalidStateError (already running) and NotAllowedError (permission denied).

Source

Thrown at packages/stage-ui/src/libs/providers/providers/browser-web-speech-api/provider.ts:382

    newRecognition.onend = sourceRecognition.onend
    recognitionInstance = newRecognition
    newRecognition.start()
    return newRecognition
  }

  function startRecognition() {
    try {
      recognition.start()
      console.info('Web Speech API recognition started successfully')
      return true
    }
    catch (error: any) {
      // Common errors:
      // - "already started": Recognition is already running
      // - "not-allowed": Microphone permission denied
      // - "service-not-allowed": Service not available
      const errorMessage = error?.message || String(error)
      console.warn('Web Speech API recognition start failed:', errorMessage, error)

      if (errorMessage.includes('already') || errorMessage.includes('started')) {
        // Recognition is already running, this is OK
        console.info('Web Speech API recognition already running')
        return true
      }

      if (errorMessage.includes('not-allowed') || errorMessage.includes('permission')) {
        // Permission denied - user needs to grant microphone access
        const err = new Error('Microphone permission denied. Please grant microphone access and try again.')
        console.error('Web Speech API: Microphone permission denied')
        fullStreamCtrl?.error(err)
        textStreamCtrl?.error(err)
        deferredText.reject(err)
        deferredText.isRejected = true
        return false
      }

View on GitHub (pinned to 677329427f)

Solutions

  1. If the log says 'already running' right after, it is benign — guard against duplicate start calls in the UI instead.
  2. Grant microphone permission for the site/app and retry from a user gesture.
  3. Check enterprise/browser policies for speech recognition service availability.
  4. For repeated non-permission failures, let the new-instance retry path run; if it also fails, capture the restartError message for support.

Example fix

// before
function startRecognition() {
  try {
    recognition.start()
    return true
  }
  catch (error: any) {
    const errorMessage = error?.message || String(error)
    ...
  }
}

// after — check running state before attempting start
function startRecognition() {
  if (isRecognitionActive()) {
    console.info('Web Speech API recognition already running')
    return true
  }
  try {
    recognition.start()
    return true
  }
  catch (error: any) {
    const errorMessage = error?.message || String(error)
    ...
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

function isRecognitionActive(): boolean {
  return recognitionActive // flag maintained in recognition.onstart/onend
}
if (isRecognitionActive()) {
  // skip start(); already running
}

Type guard

function isPermissionError(error: unknown): boolean {
  const msg = errorMessageFrom(error)
  return msg.includes('not-allowed') || msg.includes('permission')
}

Try / catch

try {
  recognition.start()
}
catch (error: any) {
  const msg = error?.message || String(error)
  if (msg.includes('already') || msg.includes('started')) return true
  if (isPermissionError(msg)) {
    // surface permission guidance to the user; do not retry
    return false
  }
  // else: new-instance retry path
}

Prevention

When it happens

Trigger: Calling start() while recognition is already active; microphone permission denied at prompt; 'service-not-allowed' when the browser's speech service is blocked; start() called from a context without user activation on browsers that require it.

Common situations: Double-invoking listen (UI race) so start runs twice; first-run permission prompt declined; enterprise policy blocking the speech service; autoplay/user-activation restrictions in embedded WebViews.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/f0d9ffd36fe7c619. Report an issue: GitHub.