{"record":{"id":"e28c6763a4384d79","repo":"SeleniumHQ/selenium","slug":"unsupported-dom-mutation-type-s-sorted-unknown","errorCode":null,"errorMessage":"Unsupported DOM mutation type(s) {sorted(unknown)}; expected a subset of {self.MUTATION_TYPES}","messagePattern":"Unsupported DOM mutation type\\(s\\) (.+?); expected a subset of (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py/private/_script_handlers.py","lineNumber":537,"sourceCode":"\n    def __init__(self, script: Any) -> None:\n        self._script = script\n        self._lock = threading.Lock()\n        self._channel: str | None = None\n        self._subscription_id: str | None = None\n        self._handlers: dict[int, frozenset[str]] = {}\n        self._preload_script_ids: list[str] = []\n        self._active_types: set[str] = set()\n\n    def _normalize_types(self, mutation_types: str | Iterable[str] | None) -> frozenset[str]:\n        if mutation_types is None:\n            return frozenset(self.DEFAULT_MUTATION_TYPES)\n        if isinstance(mutation_types, str):\n            mutation_types = (mutation_types,)\n        types = frozenset(mutation_types)\n        unknown = types - set(self.MUTATION_TYPES)\n        if unknown:\n            raise ValueError(\n                f\"Unsupported DOM mutation type(s) {sorted(unknown)}; expected a subset of {self.MUTATION_TYPES}\"\n            )\n        if not types:\n            raise ValueError(\"mutation_types must name at least one mutation type\")\n        return types\n\n    def _channel_argument(self) -> dict:\n        if self._channel is None:\n            # Stable, namespaced channel to avoid collisions with user scripts.\n            self._channel = f\"selenium.domMutation.{uuid.uuid4().hex}\"\n        return {\"type\": \"channel\", \"value\": {\"channel\": self._channel}}\n\n    def _listener_declaration(self, types: set[str]) -> str:\n        # script.addPreloadScript arguments may only be channels, so the\n        # observation options are inlined into the function declaration.\n        options = json.dumps({name: True for name in sorted(types)})\n        return \"function(channel) { return (\" + DOM_MUTATION_LISTENER_JS + \")(channel, \" + options + \"); }\"\n","sourceCodeStart":519,"sourceCodeEnd":555,"githubUrl":"https://github.com/SeleniumHQ/selenium/blob/aa36b38e696a0909e973bdf5e2f9031ffe842c4b/py/private/_script_handlers.py#L519-L555","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nhandler.add_callback(callback, mutation_types=['attribute', 'subtree'])\n\n# after\nhandler.add_callback(\n    callback, mutation_types=['attributes', 'childList', 'characterData']\n)","handlingStrategy":"validation","validationCode":"VALID = {'attributes', 'childList', 'characterData'}\ntypes_set = set(mutation_types) if mutation_types else set()\nif types_set - VALID:\n    raise ValueError(f'Invalid types: {types_set - VALID}')","typeGuard":null,"tryCatchPattern":"try:\n    handler.add_callback(callback, mutation_types=types)\nexcept ValueError as e:\n    if 'Unsupported DOM mutation' in str(e):\n        # use only 'attributes', 'childList', 'characterData'\n        types = ['attributes']\n    else:\n        raise","preventionTips":["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."],"tags":["python","bidi","dom-mutation","mutation-observer","validation"],"backgroundTag":null,"analyzedSha":"aa36b38e696a0909e973bdf5e2f9031ffe842c4b","analyzedAt":"2026-08-14T02:32:32.244Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}