calm-arm-11240
03/17/2026, 3:29 PMuseKrispNoiseFilter on LiveKit Cloud. Krisp works fine for a while, then randomly createNoiseFilter starts throwing WORKLET_NOT_SUPPORTED and it never recovers, the user has to restart the app.
The bigger problem is that once it fails, it creates an infinite retry loop. The hook catches the error and sets isNoiseFilterEnabled = false, which naturally makes our code try to re-enable it, but setNoiseFilterEnabled(true) always creates a new processor (the callback has [] deps so the closure is stale on krispProcessor) and that new processor also fails, so it loops forever spamming WORKLET_NOT_SUPPORTED / DOMException: The user aborted a request.
We also ran into a separate crash during room reconnections, processor.restart() throws inside setMediaStreamTrack but there's no catch, only a finally. So sender.replaceTrack() never runs and the mic is just dead.
Do you have any ideas on what causes createNoiseFilter to randomly start failing mid-session? This is on Electron/Chromium desktop, happens on multiple machines, no pattern we can identifytall-airline-16756
03/17/2026, 3:30 PMtall-airline-16756
03/17/2026, 3:30 PMcreateNoiseFilter randomly throwing WORKLET_NOT_SUPPORTED mid-session and causing an infinite retry loop, and (2) processor.restart() throwing during reconnections so sender.replaceTrack() never runs and the mic stays dead.
What I can confirm
• WORKLET_NOT_SUPPORTED from createNoiseFilter can happen on Electron/Chromium desktop and may appear mid-session; when it happens the noise filter doesn't automatically recover and a full app restart is needed.
• There is a defect where failed createNoiseFilter attempts can lead to an infinite retry loop: the hook sets isNoiseFilterEnabled = false on error, your code tries to re-enable it, setNoiseFilterEnabled(true) creates a new processor (the closure is stale on krispProcessor) and that new processor also fails — so it repeats and spams WORKLET_NOT_SUPPORTED / DOMException: The user aborted a request.
• During room reconnections, processor.restart() may throw inside setMediaStreamTrack. Because there’s no catch (only a finally), sender.replaceTrack() does not run and the mic remains dead.
Possible causes and what to try now
• Worklet lifecycle / environment issue in Chromium/Electron:
◦ A worklet can become unusable mid-session if the underlying AudioWorkletGlobalScope or its supporting resources are torn down or blocked by the renderer process. Electron’s Chromium version, renderer restarts, or other native modules could cause this.
◦ Conflicting native integrations or other audio-related components in the app could interfere with the worklet environment.
• Immediate mitigations you can implement client-side (safe to try now):
a. Prevent infinite retries with backoff and caps
• When createNoiseFilter fails, record the failure and do not immediately re-enable. Use exponential backoff plus a max retry count (for example: 1s, 2s, 4s, then stop and surface a user-visible error or a “Retry” button).
• This prevents the loop and reduces error spam while you gather more info.
a. Make processor lifecycle explicit and avoid relying on stale closures
• Ensure the hook or code that calls setNoiseFilterEnabled(true) references the latest krispProcessor instance (e.g., keep the processor ref in a stable ref or state that updates, avoid [] deps for callbacks that need fresh references).
• On failure, fully dispose the failed processor (stop tracks, disconnect any worklet ports) before attempting a new creation.
a. Robust error handling around restart/replaceTrack
• Wrap processor.restart() in try/catch. In the catch, attempt to recover by:
◦ disposing the processor,
◦ calling sender.replaceTrack() with the plain mic track (so audio still flows),
◦ then re-create the processor only when stable.
• Always ensure sender.replaceTrack() runs in a finally or after you’ve handled thrown errors so the mic isn’t left dead.
a. Add telemetry/logging
• Capture timestamps, Chromium/Electron version, renderer process restarts, and exact error stacks when WORKLET_NOT_SUPPORTED appears. This helps correlate the failures with environment events.
a. Fallback path for users
• Provide a fallback “disable noise suppression” option that stops trying to create the processor and continues with raw mic audio until a manual retry.
Information you can collect (these will help narrow root cause)
• Exact Electron and Chromium versions where the issue reproduces.
• Whether renderer process crashes/reloads or extension/native modules are present when the error happens.
• Full error stack traces for WORKLET_NOT_SUPPORTED and DOMException: The user aborted a request.
• Whether the problem ever resolves without a full app restart (you said it does not — confirm).
• A minimal reproduction (if possible) that toggles the noise filter repeatedly and logs the worklet state.
Short-term recommended plan
1. Add defensive handling now:
◦ Exponential backoff + max retries when createNoiseFilter fails.
◦ Catch around processor.restart() and guarantee sender.replaceTrack() runs to avoid dead mic.
◦ Make processor instance management explicit to avoid stale closures.
1. Collect the diagnostics above to help identify environmental triggers (Electron version, renderer events, other native modules).
2. If you can produce a minimal repro, share logs and versions so we can look for a pattern or a bug we can reproduce.
If you’d like, I can:
• Walk through a suggested code patch to add backoff + lifecycle fixes and show exactly where to add try/catch and processor disposal.
• Help draft the logging/telemetry you should add to capture the needed fields.
• Review a minimal repro or paste the relevant parts of your hook implementation so I can point out where the stale closure and missing catch should be changed.
Which would you prefer to do next, and can you share the Electron/Chromium versions and the hook code that manages krispProcessor?
Sources: [Flutter iOS] SoundWaveformWidget / AudioVisualizerWidget Not Working (Miss..., with interactive elementslittle-crayon-24718
03/18/2026, 8:45 AMtall-airline-16756
03/18/2026, 8:46 AMcalm-arm-11240
03/18/2026, 10:39 AMtall-airline-16756
03/18/2026, 10:39 AMcreateNoiseFilter fails so you don’t get an infinite loop.
◦ Fully dispose of a failed processor before attempting a new one (stop ports/tracks and clear refs).
• Harden reconnection logic
◦ Wrap processor.restart() in try/catch and ensure sender.replaceTrack() runs even when restart throws (either in finally or after catch recovery) so the mic can continue to send audio.
• Add targeted telemetry
◦ Log Electron/Chromium versions, Krisp version (e.g., 0.4.1), timestamps, renderer restarts, and full error stacks for WORKLET_NOT_SUPPORTED / DOMException to help correlate failures with environment events.
• Fallback UI/UX
◦ Surface a “Noise suppression disabled — retry” button after a few failed attempts so users can choose when to retry rather than having the client auto-loop.
If you want, I can:
• Show a small code patch that implements backoff + safe disposal and adds try/catch around processor.restart().
• Draft the exact telemetry fields and a short test plan to compare pre/ post-upgrade behavior.
• Review any logs you collect to help identify environmental triggers.
Which of those would be most useful right now?
, with interactive elements