SeleniumHQ/selenium · error · ValueError
mutation_types must name at least one mutation type
Error message
mutation_types must name at least one mutation type
What it means
Raised as a ValueError by _DOMMutationHandler._normalize_types() when the normalized set of mutation types is empty. After converting the input to a frozenset and validating that all values are in MUTATION_TYPES, the code checks `if not types` and throws if the frozenset has zero elements. This is distinct from the unknown-type error (110) — here all values were valid but the collection was empty.
Source
Thrown at py/private/_script_handlers.py:541
self._channel: str | None = None
self._subscription_id: str | None = None
self._handlers: dict[int, frozenset[str]] = {}
self._preload_script_ids: list[str] = []
self._active_types: set[str] = set()
def _normalize_types(self, mutation_types: str | Iterable[str] | None) -> frozenset[str]:
if mutation_types is None:
return frozenset(self.DEFAULT_MUTATION_TYPES)
if isinstance(mutation_types, str):
mutation_types = (mutation_types,)
types = frozenset(mutation_types)
unknown = types - set(self.MUTATION_TYPES)
if unknown:
raise ValueError(
f"Unsupported DOM mutation type(s) {sorted(unknown)}; expected a subset of {self.MUTATION_TYPES}"
)
if not types:
raise ValueError("mutation_types must name at least one mutation type")
return types
def _channel_argument(self) -> dict:
if self._channel is None:
# Stable, namespaced channel to avoid collisions with user scripts.
self._channel = f"selenium.domMutation.{uuid.uuid4().hex}"
return {"type": "channel", "value": {"channel": self._channel}}
def _listener_declaration(self, types: set[str]) -> str:
# script.addPreloadScript arguments may only be channels, so the
# observation options are inlined into the function declaration.
options = json.dumps({name: True for name in sorted(types)})
return "function(channel) { return (" + DOM_MUTATION_LISTENER_JS + ")(channel, " + options + "); }"
def _observe_types(self, channel_arg: dict, types: set[str]) -> None:
declaration = self._listener_declaration(types)
preload_script_id = self._script._add_preload_script(declaration, arguments=[channel_arg])
self._preload_script_ids.append(preload_script_id)View on GitHub (pinned to aa36b38e69)
Solutions
- Pass None instead of an empty list to accept the default mutation types (attributes).
- Ensure the mutation_types collection always contains at least one valid value before passing it.
- Add a guard: if your code computes the list, check `if not types: types = None` before the call.
Example fix
# before handler.add_callback(callback, mutation_types=[]) # after handler.add_callback(callback, mutation_types=None) # uses default 'attributes' # or handler.add_callback(callback, mutation_types=['attributes'])
Defensive patterns
Strategy: validation
Validate before calling
if not mutation_types:
mutation_types = None # accept default
handler.add_callback(callback, mutation_types=mutation_types) Try / catch
try:
handler.add_callback(callback, mutation_types=types)
except ValueError as e:
if 'must name at least one' in str(e):
types = ['attributes']
handler.add_callback(callback, mutation_types=types)
else:
raise Prevention
- Pass None instead of an empty list to use defaults.
- Ensure computed mutation_types lists are non-empty before passing.
- Guard with: if not types: types = None
When it happens
Trigger: Calling _normalize_types with an empty list/tuple/set: mutation_types=[] or mutation_types=set(). The frozenset of the empty iterable has zero elements, passing the unknown-type check but failing the `if not types` check.
Common situations: Programmatically constructing the mutation_types list from a filter or configuration that can produce an empty set; passing an empty list by accident; a default parameter resolution that yields [] in an edge case.
Related errors
- Unsupported DOM mutation type(s) {sorted(unknown)}; expected
- Event '{event}' not found. Available events: {self._availabl
- {self._label.capitalize()} '{handler_id}' not found
- Extra header '{name}' not found
- interval must be a positive number
AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14).
Data as JSON: /api/errors/d80ae45611c2622c.
Report an issue: GitHub.