SeleniumHQ/selenium · error · TypeError

log_level must be one of: {', '.join(levels)}

Error message

log_level must be one of: {', '.join(levels)}

What it means

Raised by the `log_level` property setter on a Selenium server runner when the assigned value is not one of the seven recognized Java logging levels (SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST). The library guards the value before storing it so the spawned `java -jar` process receives a legal `--log-level` argument. It surfaces as a TypeError because the bad input is a programmer error, not a runtime condition.

Source

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

    def version(self):
        return self._version

    @version.setter
    def version(self, version):
        if version:
            if not re.match(r"^\d+\.\d+\.\d+$", str(version)):
                raise TypeError(f"{__class__.__name__}.__init__() got an invalid version: '{version}'")
        self._version = version

    @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):

View on GitHub (pinned to aa36b38e69)

Solutions

  1. Use one of the exact canonical strings: 'SEVERE', 'WARNING', 'INFO', 'CONFIG', 'FINE', 'FINER', 'FINEST'.
  2. If sourcing the level from config, validate it against the allowed set before assigning.
  3. Map your own level vocabulary to these strings rather than passing foreign level names.

Example fix

# before
server.log_level = 'debug'

# after
server.log_level = 'FINE'
Defensive patterns

Strategy: validation

Validate before calling

LEVELS = ('SEVERE','WARNING','INFO','CONFIG','FINE','FINER','FINEST')
if level not in LEVELS:
    raise ValueError(f'bad log level {level!r}; choose from {LEVELS}')
server.log_level = level

Type guard

def is_valid_log_level(v) -> bool:
    return isinstance(v, str) and v in ('SEVERE','WARNING','INFO','CONFIG','FINE','FINER','FINEST')

Prevention

When it happens

Trigger: Assigning `server.log_level = 'DEBUG'` (or any casing/typo like 'info ' with trailing space, 'Warn', 'verbose') triggers it. The setter compares membership against the exact tuple, so only the exact canonical strings pass.

Common situations: Copy-pasting a level name from another logging framework (Python's logging.DEBUG, log4j DEBUG/TRACE) or from documentation that uses lowercase. Passing an integer level code instead of the string name.

Related errors


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