Conversation
…matched removals instrumentDOM refcounted add/removeEventListener calls without regard to listener identity or capture phase, so no-op removals (e.g. Radix DismissableLayer removing a bubble-phase listener that was added in capture phase) decremented the count and our handler was removed with the wrong capture flag, leaking it on every cycle. Track listeners per capture phase in sets so only removals that the browser would actually honor count, and always detach our handler with the capture flag it was attached with. Fixes #24702 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
size-limit report 📦
|
Member
Author
|
bugbot review |
This was referenced Sep 25, 2026
Closed
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 171dec6. Configure here.
Lms24
marked this pull request as ready for review
September 25, 2026 09:17
Lms24
requested review from
logaretm and
msonnb
and removed request for
a team
September 25, 2026 09:17
msonnb
reviewed
Sep 25, 2026
Comment on lines
+91
to
+92
| captureListeners: new Set(), | ||
| bubbleListeners: new Set(), |
Member
There was a problem hiding this comment.
m: i think this creates another subtle leakage: listeners that are added with { once: true } or aborted by passing a { signal } are automatically cleaned up by the browser and don't go through removeEventListener, thus remaining in these sets indefinitely.
Can we track if either of these are set, then remove the listener from the set if either the signal aborts or the { once: true } listener has fired? WDYT?
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes two (related) problems in our
instrumentDOMevent listener instrumentation:TIL about event listener capture modes.
We didn't differentiate between
addEventListener(fn, {capture: true})andaddEventListener(fn, {capture: false})calls, causing leakage of our event listeners when event listeners were removed with different options.=> Fixed by checking the
captureoption, registering our own listeners in the same capture config and keeping the capture option on the meta object of the event target so that we can then remove it in the correct capture configMore generally fixes an issue with
refCountwhere e.g. callingremoveEventListenerwith a callback that was never added viaaddEventListener: Browsers just ignore this call but our refCount was decremented anyway.=> Fixed by replacing the general ref count with two sets of callbacks (for both capture modes) and only removing our listener if all user-set listeners were removed
Fixes #24702
supersedes #24725
supersedes #24723