From cd765e8fdf53dd6ebd9aeaf3174614c237d45231 Mon Sep 17 00:00:00 2001 From: Bluetooth Devices Bot Date: Tue, 26 May 2026 16:54:07 +0000 Subject: [PATCH 1/2] test: pin async_remove_listener tolerance of unregistered listener Demonstrates GHSA-5pv9-xcmm-gqc7: set.remove() raises KeyError, which the except ValueError clause cannot catch. --- tests/test_handlers.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/test_handlers.py b/tests/test_handlers.py index 69f3c826..4cdc44dc 100644 --- a/tests/test_handlers.py +++ b/tests/test_handlers.py @@ -2107,3 +2107,17 @@ def async_update_records_complete(self) -> None: # This should not raise RuntimeError: set changed size during iteration zc.record_manager.async_updates_complete(False) await aiozc.async_close() + + +@pytest.mark.asyncio +async def test_async_remove_listener_missing_does_not_raise(): + """Removing a listener that was never registered must not raise.""" + + aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) + zc: Zeroconf = aiozc.zeroconf + + listener = r.RecordUpdateListener() + + zc.record_manager.async_remove_listener(listener) + + await aiozc.async_close() From fbed0b869665cbbc50411cf89d4bbf2f7f1ee72d Mon Sep 17 00:00:00 2001 From: Bluetooth Devices Bot Date: Tue, 26 May 2026 16:55:21 +0000 Subject: [PATCH 2/2] fix: tolerate removing unregistered listener (GHSA-5pv9-xcmm-gqc7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit self.listeners is a set, so .remove() raises KeyError, never ValueError — the existing except clause could not catch the only realistic failure mode. Switch to the set-native discard idiom so removing a listener that was never registered (e.g. during teardown / reconnect sequences) no longer breaks the shutdown flow. --- src/zeroconf/_handlers/record_manager.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/zeroconf/_handlers/record_manager.py b/src/zeroconf/_handlers/record_manager.py index 566f0e8c..7d3c6a66 100644 --- a/src/zeroconf/_handlers/record_manager.py +++ b/src/zeroconf/_handlers/record_manager.py @@ -214,8 +214,6 @@ def async_remove_listener(self, listener: RecordUpdateListener) -> None: This function is not threadsafe and must be called in the eventloop. """ - try: - self.listeners.remove(listener) + if listener in self.listeners: + self.listeners.discard(listener) self.zc.async_notify_all() - except ValueError as e: - log.exception("Failed to remove listener: %r", e)