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

  1. Use only the exact strings from MUTATION_TYPES: 'attributes', 'childList', or 'characterData' (case-sensitive).
  2. Pass None to accept the default ('attributes' only) if you only need attribute mutation tracking.
  3. 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

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


AI-assisted analysis of SeleniumHQ/selenium@aa36b38e69 (2026-08-14). Data as JSON: /api/errors/e28c6763a4384d79. Report an issue: GitHub.