SeleniumHQ/selenium · error · ValueError

Failed to load mutation-listener.js

Error message

Failed to load mutation-listener.js

What it means

The Log class loads mutation-listener.js from the selenium webdriver common package via pkgutil.get_data at construction time. If the resource is absent (returns None), a ValueError is raised, meaning the installed selenium package is incomplete or the resource was stripped. This indicates a packaging/corruption problem rather than normal user input.

Source

Thrown at py/selenium/webdriver/common/log.py:53


class Log:
    """Class for accessing logging APIs using the WebDriver Bidi protocol.

    This class is not to be used directly and should be used from the
    webdriver base classes.
    """

    def __init__(self, driver, bidi_session) -> None:
        self.driver = driver
        self.session = bidi_session.session
        self.cdp = bidi_session.cdp
        self.devtools = bidi_session.devtools
        _pkg = ".".join(__name__.split(".")[:-1])
        # Ensure _mutation_listener_js is not None before decoding
        _mutation_listener_js_bytes: bytes | None = pkgutil.get_data(_pkg, "mutation-listener.js")
        if _mutation_listener_js_bytes is None:
            raise ValueError("Failed to load mutation-listener.js")
        self._mutation_listener_js = _mutation_listener_js_bytes.decode("utf8").strip()

    @asynccontextmanager
    async def mutation_events(self) -> AsyncGenerator[dict[str, Any], None]:
        """Listen for mutation events and emit them as they are found.

        .. deprecated::
            Use ``driver.script.add_dom_mutation_handler()`` instead,
            which uses the WebDriver BiDi protocol.

        Example:
               async with driver.log.mutation_events() as event:
                    pages.load("dynamic.html")
                    driver.find_element(By.ID, "reveal").click()
                    WebDriverWait(driver, 5)\
                        .until(EC.visibility_of(driver.find_element(By.ID, "revealed")))

                assert event["attribute_name"] == "style"

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Reinstall selenium cleanly: `pip install --force-reinstall selenium` to restore the resource.
  2. If packaging with PyInstaller, add mutation-listener.js to package data / --add-data.
  3. Verify the file exists: check selenium/webdriver/common/mutation-listener.js in your install.
  4. Prefer the non-deprecated BiDi API driver.script.add_dom_mutation_handler() which does not need this resource.

Example fix

# before (broken install, resource missing)
async with driver.log.mutation_events() as event:  # raises at Log init
    ...

# after (use modern BiDi handler instead, no js resource needed)
await driver.script.add_dom_mutation_handler(handler)
Defensive patterns

Strategy: validation

Validate before calling

import pkgutil
_pkg = 'selenium.webdriver.common'
missing = pkgutil.get_data(_pkg, 'mutation-listener.js') is None
if missing:
    raise RuntimeError('mutation-listener.js missing; reinstall selenium or use BiDi API')

Try / catch

try:
    log = driver.log
except ValueError as e:
    if 'mutation-listener.js' in str(e):
        # packaging issue; fall back to BiDi handler
        await driver.script.add_dom_mutation_handler(handler)

Prevention

When it happens

Trigger: Constructing/accessing driver.log (the Log instance) when the mutation-listener.js resource is missing from the installed selenium distribution — e.g. a broken wheel, a partial editable install, or a zipimport/PyInstaller bundle that excludes non-.py files.

Common situations: Frozen/packaged apps (PyInstaller, cx_Freeze, zipapp) that do not include package data files. A manually edited or corrupted site-packages selenium install. Running from a source checkout where common/mutation-listener.js was deleted or not checked out.

Related errors


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