Fix RuntimeError from dict/set mutation during iteration (#3159)
authorDavid Bishop <teancom@users.noreply.github.com>
Tue, 17 Feb 2026 07:36:57 +0000 (23:36 -0800)
committerGitHub <noreply@github.com>
Tue, 17 Feb 2026 07:36:57 +0000 (08:36 +0100)
commit0c54342eb77c991621b6e14d1c617a3886aa55c4
tree9de9347e9dd1830ec830249ff34552d8318a7aa8
parentcecae5bc65247dcdc77f9f9bae499303c7739133
Fix RuntimeError from dict/set mutation during iteration (#3159)

* Fix RuntimeError from dict/set mutation during iteration

Several collections are iterated while concurrent callbacks can
modify them, causing "Set/dictionary changed size during iteration"
RuntimeErrors:

- mass.py: _subscribers set iterated in signal_event() while
  subscribe/unsubscribe callbacks modify it
- mass.py: _providers dict iterated in get_provider() and
  _on_mdns_service_state_change() while providers load/unload
- player_controller.py: _players dict iterated in get_players(),
  get_player_by_name(), and update_player_control() while players
  register/unregister
- music.py: in_progress_syncs list iterated while done-callbacks
  call .remove() on it

Snapshot via list() before iterating in all affected locations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix additional dict mutation during iteration in mass.py

Snapshot via list() in three more locations where self._providers
or self._tracked_tasks are iterated while concurrent callbacks can
modify them: get_providers(), get_providers_by_domain(), and stop().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix dict mutation during iteration in webserver dynamic routes

Snapshot self._dynamic_routes.items() via list() in _handle_catch_all()
to prevent RuntimeError when routes are registered or unregistered by
providers while a request is being matched against prefix routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------

Co-authored-by: David Bishop <git@gnuconsulting.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
music_assistant/controllers/music.py
music_assistant/controllers/players/controller.py
music_assistant/helpers/webserver.py
music_assistant/mass.py