Conversation
Two LiveKit room handlers in WebRTCConnection are async, and an emitter discards the promise a handler returns. A rejection therefore became an unhandled rejection rather than reaching the caller. TrackSubscribed is the one that matters: it awaits audioAdapter.attachRemoteTrack and setupAudioCapture, so if either fails the agent's audio never attaches, and the consumer is told nothing at all. There is no error, no disconnect, just silence. Adds onError alongside the existing onDebug on BaseConnection, and a forwardHandlerErrors helper that catches a handler's rejection and reports it. Applies it to TrackSubscribed and ActiveSpeakersChanged. onError is declared on WebRTCConnectionConfig next to onDebug so the contract is explicit rather than relying on structural pass-through. Scoped to WebRTCConnection. The issue also lists scribe.ts streamFromMicrophone, but that already catches internally, calls connection._emitError and closes, so it needs no change. Three of the four added tests fail against the previous behaviour, including one asserting no unhandled rejection is emitted. The fourth is the negative control and passes either way. Refs elevenlabs#803
PR SummaryLow Risk Overview Adds an optional Reviewed by Cursor Bugbot for commit eab4441. Bugbot is set up for automated code reviews on this repo. Configure here. |
Closes #803, for the
WebRTCConnectionhalf.The bug
Two LiveKit room handlers in
WebRTCConnectionareasync, and an emitter discards the promise a handler returns. A rejection therefore became an unhandled rejection rather than reaching the caller.TrackSubscribedis the one that matters. It awaitsaudioAdapter.attachRemoteTrackandsetupAudioCapture:If either fails, the agent's audio never attaches and the consumer is told nothing at all. No error, no disconnect, just silence, which is about the worst shape a failure can take in a voice SDK.
The fix
onErroralongside the existingonDebugonBaseConnection, plus aforwardHandlerErrorshelper that catches a handler's rejection and reports it. Applied toTrackSubscribedandActiveSpeakersChanged.onErroris declared onWebRTCConnectionConfignext toonDebug, so the contract is explicit rather than relying on the structural pass-through that currently getsonDebugto the connection.The helper lives on
BaseConnectionrather than inWebRTCConnectionbecause #803 says "and potentially others", so the next one is a one-line wrap.Scope
Only
WebRTCConnection. The issue also namesscribe.tsstreamFromMicrophone, but that already catches internally, callsconnection._emitError(error)and closes the connection, so it needs no change. Worth confirming if you had something else in mind there.Verification
Four tests added. To check they actually detect the bug rather than just passing, I reverted the helper to the previous fire-and-forget behaviour and reran:
TrackSubscribedrejection toonErrorActiveSpeakersChangedrejection toonErrorThe last is the negative control and passes either way, by design.
The unhandled-rejection test subscribes to
process.on("unhandledRejection")and asserts nothing is emitted, which is the specific symptom the issue describes.Full client package: prettier, eslint and
tsc --noEmitclean, 230 unit tests passing.Patch changeset included.