pytest-dev/pytest · error · ValueError

unknown configuration value

Error message

unknown configuration value: {name!r}

What it means

Raised by Config._getini() (src/_pytest/config/__init__.py:1806) when getini(name) is called for a name that is neither registered by an addini() call nor an alias. _parser._inidict is keyed by canonical names (config/__init__.py:1804); the KeyError at capture.py:1805 is re-raised as ValueError. This is an internal API error - external code rarely calls _getini directly.

Solutions

  1. Register the option first: call parser.addini(name, ...) in a pytest_addoption hook
  2. Check the spelling of the option name against the plugin's documentation/source
  3. If the option is from a plugin, ensure that plugin is actually enabled and its pytest_addoption ran
  4. Guard with `if name in config._parser._inidict:` before calling getini

Example fix

// before
value = config.getini('my_opt')
# nothing registered my_opt
// after
def pytest_addoption(parser):
    parser.addini('my_opt', help='...', default='x')
value = config.getini('my_opt')
Defensive patterns

Strategy: validation

Validate before calling

def ini_registered(config, name: str) -> bool:
    canonical = config._parser._ini_aliases.get(name, name)
    return canonical in config._parser._inidict

Type guard

def ini_known(config, name: str) -> bool:
    return name in config._parser._inidict or name in config._parser._ini_aliases

Try / catch

try:
    val = config.getini(name)
except ValueError:
    val = default

Prevention

When it happens

Trigger: A plugin or test calling config.getini('typo_option') where no plugin has invoked parser.addini('typo_option', ...). The lookup at config/__init__.py:1804 raises KeyError and capture.py:1805-1806 wraps it.

Common situations: Typos in plugin code that reads its own ini option; calling getini before pytest_addoption has registered it; renaming an ini option without updating all call sites; a third-party plugin removed/renamed an option your conftest reads.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/cb2703f7872a85c2. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/config/__init__.py:1806

        self._inicache[canonical_name] = val = self._getini(canonical_name)
        return val

    # Meant for easy monkeypatching by legacypath plugin.
    # Can be inlined back (with no cover removed) once legacypath is gone.
    def _getini_unknown_type(self, name: str, type: str, value: object):
        msg = (
            f"Option {name} has unknown configuration type {type} with value {value!r}"
        )
        raise ValueError(msg)  # pragma: no cover

    def _getini(self, name: str):
        # If this is an alias, resolve to canonical name.
        canonical_name = self._parser._ini_aliases.get(name, name)

        try:
            _description, type, default = self._parser._inidict[canonical_name]
        except KeyError as e:
            raise ValueError(f"unknown configuration value: {name!r}") from e

        # Collect all possible values (canonical name + aliases) from _inicfg.
        # Each candidate is (ConfigValue, is_canonical).
        candidates = []
        if canonical_name in self._inicfg:
            candidates.append((self._inicfg[canonical_name], True))
        for alias, target in self._parser._ini_aliases.items():
            if target == canonical_name and alias in self._inicfg:
                candidates.append((self._inicfg[alias], False))

        if not candidates:
            return default

        # Pick the best candidate based on precedence:
        # 1. CLI override takes precedence over file, then
        # 2. Canonical name takes precedence over alias.
        selected = max(candidates, key=lambda x: (x[0].origin == "override", x[1]))[0]
        value = selected.value

View on GitHub (pinned to 0d6fbdeffa)