{"record":{"id":"b3c772e2642f936b","repo":"moeru-ai/airi","slug":"web-speech-api-recognition-did-not-start-immediate-b3c772","errorCode":null,"errorMessage":"Web Speech API recognition did not start immediately. This might be due to:","messagePattern":"Web Speech API recognition did not start immediately\\. This might be due to:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/provider-inference/src/providers/local/browser-web-speech-api/provider.ts","lineNumber":457,"sourceCode":"  }\n\n  recognition.onsoundend = () => {\n    console.info('Web Speech API sound ended')\n  }\n\n  recognition.onaudioend = () => {\n    console.info('Web Speech API audio capture ended')\n  }\n\n  recognition.onnomatch = () => {\n    console.info('Web Speech API: No speech match')\n  }\n\n  const started = startRecognition()\n  if (!started) {\n    // If immediate start failed, it might be a permission issue\n    // Web Speech API will prompt for permission automatically, so we just log\n    console.warn('Web Speech API recognition did not start immediately. This might be due to:')\n    console.warn('1. Microphone permission not granted - browser should prompt automatically')\n    console.warn('2. Recognition already running - this is normal if called multiple times')\n    console.warn('3. Browser requires user gesture - ensure microphone was enabled by user action')\n\n    // Don't retry immediately - wait for permission or user action\n    // The recognition instance is already created, so it can be started later if needed\n  }\n\n  return {\n    fullStream,\n    text: deferredText.promise,\n    textStream,\n    recognition: recognitionInstance,\n  }\n}\n","sourceCodeStart":439,"sourceCodeEnd":473,"githubUrl":"https://github.com/moeru-ai/airi/blob/f679616c34f1cf6d282c8d64264242af944b3fed/packages/provider-inference/src/providers/local/browser-web-speech-api/provider.ts#L439-L473","documentation":"This is a diagnostic `console.warn` (not an exception) emitted by `streamWebSpeechAPITranscription` when `startRecognition()` returned false, meaning the Web Speech API `recognition.start()` did not succeed immediately. It lists the three likely causes: missing microphone permission, an already-running recognition instance, or the browser requiring a user gesture. The stream is not rejected here; the code deliberately waits for permission or user action instead of retrying.","triggerScenarios":"Calling `streamWebSpeechAPITranscription` (via `result`) in a browser where `recognition.start()` fails synchronously or asynchronously and the error is not classified as 'already started' or 'permission denied' by the handler, so `startRecognition` returns false.","commonSituations":"Calling transcription before any user interaction on a page that requires a gesture; the browser's mic permission prompt is pending or was dismissed; the recognizer was started twice without stopping the first instance; running in a browser/WebView without full Web Speech API support.","solutions":["Trigger the transcription call from an explicit user gesture (button click) so the mic permission prompt can be shown and granted.","Check mic permission state with `navigator.permissions.query({ name: 'microphone' })` and guide the user to grant access in site settings.","Ensure only one recognition instance runs at a time; call `stop()` before starting a new session.","Check the DevTools console for the preceding 'recognition start failed' warning, which names the concrete cause."],"exampleFix":"// before\nconst result = await streamWebSpeechAPITranscription(...)\n\n// after\nconst perm = await navigator.permissions.query({ name: 'microphone' })\nif (perm.state !== 'granted') {\n  await requestMicPermissionViaUserGesture() // must run inside a click handler\n}\nconst result = await streamWebSpeechAPITranscription(...)","handlingStrategy":"retry","validationCode":"const canUseSpeech = typeof window !== 'undefined' && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window)\nconst perm = await navigator.permissions.query({ name: 'microphone' })\nif (perm.state === 'denied') throw new Error('Microphone permission denied')","typeGuard":"function isSpeechApiSupported(): boolean { return typeof window !== 'undefined' && ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) }","tryCatchPattern":"try {\n  const session = await streamWebSpeechAPITranscription(...)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('permission')) {\n    showMicPermissionHelp(); return\n  }\n  // non-fatal: start may simply be deferred — await session.text with timeout\n  throw error\n}","preventionTips":["Always start transcription from a user gesture so the mic prompt can appear.","Pre-check microphone permission with the Permissions API and surface a settings hint when denied.","Verify Web Speech API support in the target browser/WebView before offering voice input.","Watch the session streams for error events rather than relying on immediate start success."],"tags":["web-speech-api","microphone","browser","diagnostic"],"backgroundTag":"speech-recognition-start-failed","analyzedSha":"f679616c34f1cf6d282c8d64264242af944b3fed","analyzedAt":"2026-09-08T13:18:15.005Z","contentChangedAt":"2026-09-08T13:18:15.005Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}