Skip to content

fix(chat): stop the voice-input recognizer from busy-looping on a fatal error - #6451

Merged
pedrofrxncx merged 1 commit into
mainfrom
fix/voice-input-fatal-error-restart-loop-w3
Aug 24, 2026
Merged

fix(chat): stop the voice-input recognizer from busy-looping on a fatal error#6451
pedrofrxncx merged 1 commit into
mainfrom
fix/voice-input-fatal-error-restart-loop-w3

Conversation

@pedrofrxncx

@pedrofrxncx pedrofrxncx commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Bug found while reviewing the chat input area for error resilience under network hiccups: useVoiceInput (used by the chat composer's mic button, apps/web/src/components/chat/input.tsx) never attached an onerror handler to the Web Speech SpeechRecognition instance.

recognition.onend restarts the recognizer whenever isRecordingRef.current is still true — that's needed so continuous dictation survives the routine gaps between phrases. But with no onerror handler, the same restart also fires after a fatal error: a dropped network connection (most SpeechRecognition implementations are cloud-backed), the mic being unplugged, or the OS revoking mic permission mid-recording. Each restart immediately re-fails with the identical error, so the hook busy-loops indefinitely and the UI is stuck showing "recording" with no way out short of a page reload.

Fix: add an onerror handler. no-speech is left alone (it's routine in continuous mode, onend already restarts it correctly). Any other error code stops the recognizer, tears down the visualizer, and returns status to idle (or permission-denied for not-allowed) instead of retrying forever.

Failure scenario: start voice input, then simulate a network/audio-capture/not-allowed error from the recognizer — before this fix status stays recording forever and recognition.start() gets called again on every onend; after the fix it settles to idle and stops restarting. Covered by the new test stops recording instead of busy-looping restarts on a fatal recognition error in apps/web/src/hooks/use-voice-input.test.ts.

Reviewer check: bun test apps/web/src/hooks/use-voice-input.test.ts (4 pass), cd apps/web && bunx tsc --noEmit, bunx oxlint apps/web/src/hooks/use-voice-input.ts apps/web/src/hooks/use-voice-input.test.ts — all green locally; full CI covers the rest.


Summary by cubic

Stops the chat mic’s voice input from busy-looping after a fatal Web Speech error by handling SpeechRecognition.onerror. Previously onend always restarted recognition and left status stuck at recording; now we ignore no-speech, stop on other errors, tear down the visualizer, and set status to idle or permission-denied.

  • Add recognition.onerror: ignore no-speech; for other errors set status to idle or permission-denied (not-allowed), clear recognitionRef, stop the visualizer, and prevent onend from auto-restarting.
  • Keep continuous dictation behavior: onend still restarts only when recording continues and no fatal error occurred.
  • Add a unit test that reproduces fatal error scenarios and asserts no restart; see apps/web/src/hooks/use-voice-input.test.ts.

Written for commit 8e2e04b. Summary will update on new commits.

Review in cubic

…al error

Web Speech recognition had no onerror handler, so onend's auto-restart
(used to keep dictation going through routine no-speech gaps) would
also kick in after a fatal error - a dropped network connection, the
mic disconnecting, or the OS revoking mic permission mid-recording.
Each restart immediately re-fails with the same error, so the hook
busy-loops indefinitely while the UI stays stuck showing 'recording'
with no way out but a page reload.

Add an onerror handler: no-speech is left alone (onend already
restarts it, this is normal in continuous mode), anything else stops
the recognizer and returns status to idle/permission-denied instead
of retrying forever.
@pedrofrxncx
pedrofrxncx merged commit 829e6b0 into main Aug 24, 2026
34 checks passed
@pedrofrxncx
pedrofrxncx deleted the fix/voice-input-fatal-error-restart-loop-w3 branch August 24, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant