{"record":{"id":"60d38261e2a9d171","repo":"moeru-ai/airi","slug":"error-stopping-web-speech-api-recognition","errorCode":null,"errorMessage":"Error stopping Web Speech API recognition:","messagePattern":"Error stopping Web Speech API recognition:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/stage-ui/src/stores/modules/hearing.ts","lineNumber":675,"sourceCode":"      asrSpan = undefined\n    }\n\n    // Special handling for Web Speech API\n    if (session.providerId === 'browser-web-speech-api') {\n      try {\n        const reason = new DOMException(abort ? 'Aborted' : 'Stopped', 'AbortError')\n        if (!session.abortController.signal.aborted) {\n          session.abortController.abort(reason)\n        }\n\n        // Stop Web Speech API recognition if it exists\n        const result = session.result as any\n        if (result?.recognition) {\n          try {\n            result.recognition.stop()\n          }\n          catch (err) {\n            console.warn('Error stopping Web Speech API recognition:', err)\n          }\n        }\n      }\n      catch (err) {\n        console.error('Error stopping Web Speech API session:', err)\n      }\n\n      if (session.idleTimer)\n        clearTimeout(session.idleTimer)\n\n      streamingSession.value = undefined\n\n      if (session.result?.mode === 'stream') {\n        try {\n          const text = await session.result.text\n          return text\n        }\n        catch (err) {","sourceCodeStart":657,"sourceCodeEnd":693,"githubUrl":"https://github.com/moeru-ai/airi/blob/f679616c34f1cf6d282c8d64264242af944b3fed/packages/stage-ui/src/stores/modules/hearing.ts#L657-L693","documentation":"During hearing-session teardown, result.recognition.stop() on the embedded Web Speech API recognition threw — commonly an InvalidStateError because recognition already ended or was aborted. It is caught in a nested try so teardown continues: the idle timer is cleared and streamingSession is cleared regardless. The recognition instance is discarded either way, so the warning is cosmetic.","triggerScenarios":"Mic start/stop toggled rapidly so stop() runs after recognition already ended; recognition auto-disconnected (tab switch, permission revoked) before teardown; abort fired first and stop() then throws InvalidStateError.","commonSituations":"Push-to-talk toggled quickly; browser revoking mic permission mid-session; Safari/Chrome differences in Web Speech lifecycle.","solutions":["Ignore it — the recognition instance is discarded anyway and teardown completed","Guard stop() with the recognition state or drop the reference before calling stop","Debounce rapid start/stop of the mic to avoid double-stop races","Abort the session controller first and skip stop() when the signal already aborted"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const result = session.result as any\nif (!result?.recognition) return // no embedded Web Speech instance to stop","typeGuard":null,"tryCatchPattern":"try {\n  result.recognition.stop()\n}\ncatch (err) {\n  // InvalidStateError is expected when recognition already ended; teardown continues\n  console.warn('Error stopping Web Speech API recognition:', err)\n}","preventionTips":["Abort via the AbortController first, then stop() recognition, to avoid double-stop races","Debounce rapid start/stop toggles of the mic","Drop the recognition reference as soon as stop() is attempted"],"tags":["hearing","web-speech-api","stop","teardown"],"backgroundTag":"web-speech-api-invalid-state","analyzedSha":"f679616c34f1cf6d282c8d64264242af944b3fed","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}