Summary
Room._on_room_event raises KeyError in the track_subscribed handler when the remote participant has already been removed from self._remote_participants by a racing participant_disconnected (or a duplicate event). This is the same class of race that #743 fixed for track_unpublished, but the sibling handlers were left using an unguarded dict lookup.
Traceback (observed in production)
KeyError: 'sip-caller-+91XXXXXXXXXX'
File ".../livekit/rtc/room.py", in _listen_task
self._on_room_event(event.room_event)
File ".../livekit/rtc/room.py", in _on_room_event
rparticipant = self._remote_participants[event.track_subscribed.participant_identity]
It is caught by the except Exception: logging.exception(...) in _listen_task, so it does not crash the session, but it is logged as an error and reported to Sentry as noise. It shows up most often with SIP participants, whose connect/disconnect ordering is racier than typical WebRTC clients (a fast caller hangup interleaves participant_disconnected with an in-flight track_subscribed).
Root cause
On main (livekit-rtc 1.1.13), track_unpublished was made defensive in #743 with an explicit comment:
# The participant or publication may already have been removed by a
# racing disconnect or a duplicate event, so both lookups are done
# defensively ... instead of raising a KeyError that _listen_task logs as an error.
rp = self._remote_participants.get(identity)
if rp is not None:
...
but the following handlers in the same method still use a raw self._remote_participants[identity] and hit the identical race:
track_published
track_subscribed ← the one in the traceback above
track_unsubscribed
track_subscription_failed
Expected behavior
These handlers should look the participant (and publication) up defensively and skip the emit when the entry is already gone, mirroring track_unpublished / local_track_unpublished, rather than raising a KeyError.
Environment
- livekit-rtc: 1.1.8 (observed); confirmed still present on
main (1.1.13)
- Python 3.11
Happy to send a PR mirroring the #743 approach.
Summary
Room._on_room_eventraisesKeyErrorin thetrack_subscribedhandler when the remote participant has already been removed fromself._remote_participantsby a racingparticipant_disconnected(or a duplicate event). This is the same class of race that #743 fixed fortrack_unpublished, but the sibling handlers were left using an unguarded dict lookup.Traceback (observed in production)
It is caught by the
except Exception: logging.exception(...)in_listen_task, so it does not crash the session, but it is logged as an error and reported to Sentry as noise. It shows up most often with SIP participants, whose connect/disconnect ordering is racier than typical WebRTC clients (a fast caller hangup interleavesparticipant_disconnectedwith an in-flighttrack_subscribed).Root cause
On
main(livekit-rtc 1.1.13),track_unpublishedwas made defensive in #743 with an explicit comment:but the following handlers in the same method still use a raw
self._remote_participants[identity]and hit the identical race:track_publishedtrack_subscribed← the one in the traceback abovetrack_unsubscribedtrack_subscription_failedExpected behavior
These handlers should look the participant (and publication) up defensively and skip the emit when the entry is already gone, mirroring
track_unpublished/local_track_unpublished, rather than raising aKeyError.Environment
main(1.1.13)Happy to send a PR mirroring the #743 approach.