pytest-dev/pytest · error · ValueError
invalid type for ini option
Error message
invalid type for ini option {name!r}: Literal choices must be strings, got {choices!r} What it means
Raised by _ini_type_to_member() during addini() when a Literal type is used for the type argument but not all of its choices are strings. Literal types for ini options must contain only str choices. The error names the invalid choices.
Solutions
- Ensure all Literal choices are strings: change Literal['fast', 42] to Literal['fast', '42']
- If numeric values are needed, use type='string' and validate in your plugin code
- Use a union of recognized scalar types (int | str) instead of Literal for mixed numeric/string input
Example fix
# before
parser.addini('mode', type=Literal['fast', 42])
# after
parser.addini('mode', type=Literal['fast', '42']) Defensive patterns
Strategy: type-guard
Validate before calling
from typing import get_args, get_origin, Literal
def validate_literal_choices(type_: object) -> bool:
if get_origin(type_) is Literal:
choices = get_args(type_)
return all(isinstance(c, str) for c in choices)
return True Type guard
from typing import get_args, get_origin, Literal
def is_string_literal(type_: object) -> bool:
if get_origin(type_) is not Literal:
return False
return all(isinstance(c, str) for c in get_args(type_)) Prevention
- Ensure all Literal choices are strings: Literal['a', 'b']
- Do not mix string and non-string choices in a Literal type
- Use a union type (int | str) if numeric input is needed instead of Literal
When it happens
Trigger: Calling parser.addini('mode', type=Literal['fast', 42]) — the integer 42 is not a string. The check `all(isinstance(choice, str) for choice in choices)` fails inside the get_origin(type_) is Literal branch.
Common situations: Mixing string and non-string choices in a Literal type. Using Literal[int, str] expecting numeric support. Copying a Literal from application code that includes non-string members.
Related errors
- ini option has a type, which has no implicit default; pass…
- invalid type for ini option
- alias conflicts with existing configuration option
- is already an alias of
- no option named
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/04a60174c1336e08.
Report an issue: GitHub.
Appendix: 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 0d6fbdeffa)