SeleniumHQ/selenium · error · ValueError
Unsupported DOM mutation type(s) {sorted(unknown)}; expected
Error message
Unsupported DOM mutation type(s) {sorted(unknown)}; expected a subset of {self.MUTATION_TYPES} What it means
Raised as a ValueError by _DOMMutationHandler._normalize_types() when the provided mutation_types contains one or more values not in MUTATION_TYPES, which is the tuple ('attributes', 'childList', 'characterData') — the three MutationObserver options from the DOM standard. The unknown values are computed as `types - set(self.MUTATION_TYPES)` and the sorted list is included in the error message along with the valid set.
Source
Thrown at py/private/_script_handlers.py:537
def __init__(self, script: Any) -> None:
self._script = script
self._lock = threading.Lock()
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 + "); }"
View on GitHub (pinned to aa36b38e69)
Solutions
- Use only the exact strings from MUTATION_TYPES: 'attributes', 'childList', or 'characterData' (case-sensitive).
- Pass None to accept the default ('attributes' only) if you only need attribute mutation tracking.
- If you need to observe subtree changes, note that 'subtree' is not supported — combine the three valid types instead.
Example fix
# before
handler.add_callback(callback, mutation_types=['attribute', 'subtree'])
# after
handler.add_callback(
callback, mutation_types=['attributes', 'childList', 'characterData']
) Defensive patterns
Strategy: validation
Validate before calling
VALID = {'attributes', 'childList', 'characterData'}
types_set = set(mutation_types) if mutation_types else set()
if types_set - VALID:
raise ValueError(f'Invalid types: {types_set - VALID}') Try / catch
try:
handler.add_callback(callback, mutation_types=types)
except ValueError as e:
if 'Unsupported DOM mutation' in str(e):
# use only 'attributes', 'childList', 'characterData'
types = ['attributes']
else:
raise Prevention
- Use only the exact strings: 'attributes', 'childList', 'characterData'.
- Pass None for the default (attributes) rather than guessing.
- Define a constant set of valid types in your test helpers.
When it happens
Trigger: Calling dom_mutation_handler.add_callback(callback, mutation_types=['attribute', 'subtree']) or similar where 'attribute' (should be 'attributes') or 'subtree' (not a valid mutation type) are passed. Any value outside the exact three strings triggers the error.
Common situations: Misspelling 'attributes' as 'attribute'; including 'subtree' or 'oldValue' which are MutationObserver options but not in MUTATION_TYPES; using camelCase or different casing than the exact tuple values; confusing general MutationObserver options with the supported subset.
Related errors
- mutation_types must name at least one mutation type
- 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/e28c6763a4384d79.
Report an issue: GitHub.