pytest-dev/pytest · error · UsageError

: config option ' ' expects one of , got

Error message

{self.inipath}: config option '{name}' expects one of {_ini_type_repr(type)}, got {value!r}

What it means

Raised by _getini_value() at config/__init__.py:1868-1872 when an ini option registered with a Literal[...] type receives a string that is NOT one of the registered choices. _IniLiteral.choices (argparsing.py:50) holds the allowed strings; capture.py:1868 checks membership and raises ValueError, which is converted to UsageError by the outer handler at config/__init__.py:1847-1848. _ini_type_repr() (argparsing.py:95) renders the allowed choices in the message.

Solutions

  1. Use one of the choices listed in the error message (rendered by _ini_type_repr)
  2. Check the plugin's changelog if a previously valid choice was removed
  3. Match case exactly - Literal membership is case-sensitive string equality
  4. If you need more flexibility, request the plugin author switch from Literal to a free-form string with custom validation

Example fix

// before
# pytest.ini
[pytest]
log_cli_level = VERBOSE
// after
[pytest]
log_cli_level = DEBUG
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {'DEBUG','INFO','WARNING','ERROR','CRITICAL'}  # example
if value not in ALLOWED:
    raise ValueError(f'log_level must be one of {ALLOWED}, got {value!r}')

Type guard

def in_choices(value: str, choices) -> bool:
    return value in choices

Try / catch

from _pytest.config import UsageError
try:
    val = config.getini('mode')
except UsageError as e:
    # message lists valid choices via _ini_type_repr
    print(e)

Prevention

When it happens

Trigger: A plugin registers addini('mode', type=Literal['a','b','c']) and the user writes `mode = 'd'`. capture.py:1868 returns False for membership and capture.py:1869-1872 raises.

Common situations: Typos in option values; using a value valid in an older plugin version that was since removed from the Literal; case-sensitivity mismatches (e.g. 'Debug' vs 'DEBUG'); copy-paste from another tool's config.

Related errors


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

Appendix: source

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

        self,
        mode: Literal["ini", "toml"],
        name: str,
        canonical_name: str,
        type: str | _IniLiteral,
        value: object,
        default: Any,
    ):
        """Convert a config value, read in the given mode, to the option's type."""
        if isinstance(type, _IniLiteral):
            # A Literal value is a plain string checked against the registered
            # choices, without coercion, in both ini and toml modes.
            if not isinstance(value, str):
                raise TypeError(
                    f"{self.inipath}: config option '{name}' expects a string, "
                    f"got {builtins.type(value).__name__}: {value!r}"
                )
            if value not in type.choices:
                raise ValueError(
                    f"{self.inipath}: config option '{name}' expects one of "
                    f"{_ini_type_repr(type)}, got {value!r}"
                )
            return value
        if mode == "ini":
            # In ini mode, values are always str | list[str].
            assert isinstance(value, (str, list))
            return self._getini_ini(name, canonical_name, type, value, default)
        elif mode == "toml":
            return self._getini_toml(name, canonical_name, type, value, default)
        else:
            assert_never(mode)

    def _getini_ini(
        self,
        name: str,
        canonical_name: str,
        type: str,

View on GitHub (pinned to 0d6fbdeffa)