moeru-ai/airi · info

2. Recognition already running - this is normal if called mu

Error message

2. Recognition already running - this is normal if called multiple times

What it means

Line 3 of the multi-line diagnostic `console.warn` block in `streamWebSpeechAPITranscription`, emitted when recognition did not start immediately. This line notes that the recognition instance may already be running, which is normal when the transcription function is called multiple times without stopping the previous session. It is informational; the provider's start handler explicitly treats 'already started' errors as OK and returns true.

Source

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

  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. Track the active recognition instance and call `stop()` (or `abort()`) before starting a new session.
  2. Guard the start with an `isListening` flag so repeated invocations are ignored while a session is live.
  3. Debounce or disable the mic button while transcription is in progress.
  4. The provider already tolerates 'already started' — if you see this warning with working audio, it can safely be ignored.

Example fix

// before
micButton.onclick = () => streamWebSpeechAPITranscription(...)

// after
let activeSession = null
micButton.onclick = async () => {
  if (activeSession) return
  activeSession = await streamWebSpeechAPITranscription(...)
  activeSession.text.finally(() => { activeSession = null })
}
Defensive patterns

Strategy: validation

Validate before calling

let isListening = false
async function safeStart() {
  if (isListening) return
  isListening = true
  try { await startTranscription() } finally { /* reset in onend/onerror */ }
}

Type guard

function isRecognitionActive(instance: SpeechRecognition | null): instance is SpeechRecognition { return instance !== null }

Try / catch

// not-throwing path: guard start calls instead
if (isListening) return existingSession
try {
  session = await streamWebSpeechAPITranscription(...)
} finally {
  session.text.finally(() => { isListening = false })
}

Prevention

When it happens

Trigger: Calling `streamWebSpeechAPITranscription` (or `recognition.start()`) while a previous `SpeechRecognition` instance is still active; rapid re-invocation of `result` without awaiting stream completion or calling `stop()`.

Common situations: Double-clicking the mic button; re-entering a voice UI while a session is live; component remount creating a second recognizer; hot module reload leaving an orphan recognition instance.

Related errors


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