SeleniumHQ/selenium · error · TypeError

env must be a mapping of environment variables

Error message

env must be a mapping of environment variables

What it means

Raised by the `env` property setter when the value is not None and is not a `collections.abc.Mapping`. The server runner passes `env` straight into `subprocess.Popen`, which requires a dict-like environment; the guard rejects incompatible types before the process spawn. It is a TypeError signaling incorrect caller usage.

Source

Thrown at py/selenium/webdriver/remote/server.py:146

    @property
    def log_level(self):
        return self._log_level

    @log_level.setter
    def log_level(self, log_level):
        levels = ("SEVERE", "WARNING", "INFO", "CONFIG", "FINE", "FINER", "FINEST")
        if log_level not in levels:
            raise TypeError(f"log_level must be one of: {', '.join(levels)}")
        self._log_level = log_level

    @property
    def env(self):
        return self._env

    @env.setter
    def env(self, env):
        if env is not None and not isinstance(env, collections.abc.Mapping):
            raise TypeError("env must be a mapping of environment variables")
        self._env = env

    @property
    def java_path(self):
        return self._java_path

    @java_path.setter
    def java_path(self, java_path):
        if java_path and not os.path.exists(java_path):
            raise OSError(f"Can't find java executable located at {java_path}")
        self._java_path = java_path

    def _wait_for_server(self, timeout=10):
        start = time.time()
        while time.time() - start < timeout:
            try:
                urllib.request.urlopen(self.status_url)
                return True

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Pass a dict (or any Mapping) of name->value, e.g. {'JAVA_OPTS': '-Xmx2g'}.
  2. Convert a list of 'K=V' strings into a dict before assigning: dict(kv.split('=',1) for kv in lst).
  3. Pass None (or simply don't set it) to inherit the current process environment.

Example fix

# before
server.env = ['DISPLAY=:0', 'JAVA_OPTS=-Xmx2g']

# after
server.env = {'DISPLAY': ':0', 'JAVA_OPTS': '-Xmx2g'}
Defensive patterns

Strategy: type-guard

Validate before calling

import collections.abc
if env is not None and not isinstance(env, collections.abc.Mapping):
    raise TypeError('env must be a Mapping of name->value')
server.env = env

Type guard

def is_env_mapping(env) -> bool:
    return env is None or isinstance(env, collections.abc.Mapping)

Prevention

When it happens

Trigger: Assigning `server.env = ['FOO=bar']` (list of strings, a shell-export style), a tuple, a set, or a plain string. Also assigning a custom object that does not register as a Mapping even if it is dict-like.

Common situations: Translating a shell-style env list (`['A=1','B=2']`) into the env setter. Reusing a JSON-loaded structure that turned out to be a list rather than an object. Passing os.environ is fine (it is a Mapping).

Related errors


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