Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions livekit-rtc/livekit/rtc/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -821,11 +821,22 @@ def _on_room_event(self, event: proto_room.RoomEvent) -> None:
rparticipant._track_publications[rpublication.sid] = rpublication
self.emit("track_published", rpublication, rparticipant)
elif which == "track_unpublished":
rparticipant = self._remote_participants[event.track_unpublished.participant_identity]
rpublication = rparticipant._track_publications.pop(
event.track_unpublished.publication_sid
)
self.emit("track_unpublished", rpublication, rparticipant)
# The participant or publication may already have been removed by a
# racing disconnect or a duplicate event, so both lookups are done
# defensively and the emit is skipped when the entry is gone,
# mirroring the local_track_unpublished handler, instead of raising a
# KeyError that _listen_task logs as an error.
identity = event.track_unpublished.participant_identity
sid = event.track_unpublished.publication_sid
rparticipant = self._remote_participants.get(identity)
if rparticipant is not None:
rpublication = rparticipant._track_publications.pop(sid, None)
if rpublication is not None:
self.emit("track_unpublished", rpublication, rparticipant)
else:
logging.debug("track_unpublished for untracked publication sid %s", sid)
Comment thread
davidzhao marked this conversation as resolved.
Outdated
else:
logging.debug("track_unpublished for untracked participant %s", identity)
elif which == "track_subscribed":
owned_track_info = event.track_subscribed.track
track_info = owned_track_info.info
Comment on lines 841 to 843

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 Other remote-track event handlers still use hard dictionary lookups and may crash under the same race conditions

This PR defensively handles the case where track_unpublished arrives after the participant or publication has already been removed. However, the same race condition (participant disconnected before event is processed) could affect track_unsubscribed (room.py:857-858), track_subscribed (room.py:843-844), track_subscription_failed (room.py:867-868), track_muted (room.py:879), and track_unmuted (room.py:890), all of which still use hard [] lookups on self._remote_participants and track_publications. If the fix here is warranted, the same defensive pattern may be needed in those handlers to avoid KeyError crashes in _listen_task.

(Refers to lines 840-865)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Expand Down
Loading