pytest-dev/pytest · error · ValueError
invalid type for ini option {name!r}: Literal choices must b
Error message
invalid type for ini option {name!r}: Literal choices must be strings, got {choices!r} What it means
Raised by Parser.addini() when the type= argument is a typing.Literal whose choices include non-string values. pytest's ini subsystem only supports Literal enumerations of strings because ini-style config files are fundamentally string-based.
Source
Thrown at src/_pytest/config/argparsing.py:87
def _ini_type_to_tag(name: str, type_: object) -> _IniTypeTag:
"""Normalize one member of an `addini(type=...)` argument to a string tag."""
try:
return _INI_TYPES[type_]
except (KeyError, TypeError): # TypeError: unhashable type_
raise ValueError(
f"invalid type for ini option {name!r}: {type_!r} (expected one of "
f"{', '.join(repr(tag) for tag in get_args(_IniTypeTag))}, one of "
"the types str, bool, int, float, a union of these types such as "
"`int | str`, or a `Literal` of strings)"
) from None
def _ini_type_to_member(name: str, type_: object) -> _IniTypeTag | _IniLiteral:
"""Normalize one member of an `addini(type=...)` argument."""
if get_origin(type_) is Literal:
choices = get_args(type_)
if not all(isinstance(choice, str) for choice in choices):
raise ValueError(
f"invalid type for ini option {name!r}: Literal choices "
f"must be strings, got {choices!r}"
)
return _IniLiteral(choices)
return _ini_type_to_tag(name, type_)
def _ini_type_repr(type: IniType) -> str:
"""Render an ini option type for --help output and error messages."""
if isinstance(type, _IniLiteral):
return " | ".join(repr(choice) for choice in type.choices)
if isinstance(type, tuple):
return " | ".join(_ini_type_repr(member) for member in type)
return type
def _get_argparse_dest(opts: Sequence[str]) -> str:
long_opts = [opt for opt in opts if opt.startswith("--")]View on GitHub (pinned to 98b357f69e)
Solutions
- Restrict Literal choices to strings only: Literal['1', '2', '3'].
- Use type=int | str with manual validation if you need numeric acceptance.
- Keep choices as strings and convert to the desired type when reading via config.getini().
Example fix
# before
parser.addini('level', type=Literal[1, 2, 3], help='verbosity')
# after
parser.addini('level', type=Literal['1', '2', '3'], help='verbosity') Defensive patterns
Strategy: type-guard
Validate before calling
from typing import get_origin, get_args, Literal
def validate_literal_choices(type_: object) -> None:
if get_origin(type_) is Literal:
choices = get_args(type_)
bad = [c for c in choices if not isinstance(c, str)]
if bad:
raise TypeError(f'Literal choices must be strings, got {bad!r}') Type guard
from typing import get_origin, get_args, Literal
def is_string_literal(type_: object) -> bool:
return get_origin(type_) is Literal and all(isinstance(c, str) for c in get_args(type_)) Prevention
- Keep Literal choices string-only; coerce numerics in your reader code.
- Add a plugin-load test exercising each addini call.
When it happens
Trigger: Calling parser.addini('mode', type=Literal['fast', 'slow']) is fine, but parser.addini('mode', type=Literal['fast', 2]) or type=Literal[1, 2, 3] raises this because not every choice isinstance(str).
Common situations: Plugin authors wanting an int/bool enum via Literal; mixing string and numeric literal values expecting automatic coercion.
Related errors
- invalid type for ini option {name!r}: {type_!r} (expected on
- ini option {name!r} has a {kind} type, which has no implicit
- alias {alias!r} conflicts with existing configuration option
- {alias!r} is already an alias of {already!r}
- help argument cannot be None for {name}
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/04a60174c1336e08.json.
Report an issue: GitHub.