pytest-dev/pytest · error · ValueError

invalid type for ini option {name!r}: {type_!r} (expected on

Error message

invalid type for ini option {name!r}: {type_!r} (expected one of {tags}, one of the types str, bool, int, float, a union of these types such as `int | str`, or a `Literal` of strings)

What it means

Raised by Parser.addini() when the type= argument is not one of the accepted forms: a string tag ('string','paths','pathlist','args','linelist','bool','int','float'), one of the Python types str/bool/int/float, a union of these (e.g. int | str), or a typing.Literal of strings. Any other value triggers this ValueError at plugin registration time.

Source

Thrown at src/_pytest/config/argparsing.py:74

#: ``int | str``).
IniType: TypeAlias = _IniTypeTag | _IniLiteral | tuple[_IniTypeTag | _IniLiteral, ...]

#: Maps each string tag or plain Python type accepted by :meth:`Parser.addini`
#: for its ``type`` argument to the normalized string tag.
_INI_TYPES: dict[object, _IniTypeTag] = {tag: tag for tag in get_args(_IniTypeTag)} | {
    str: "string",
    bool: "bool",
    int: "int",
    float: "float",
}


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_)

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Use one of the supported string tags: 'string', 'paths', 'pathlist', 'args', 'linelist', 'bool', 'int', 'float'.
  2. For multiple accepted types use a union like `int | str` or `str | bool`.
  3. For enumerated string values use Literal['a','b','c'].
  4. For complex parsing, use type='string' and post-process the value in a pytest_load_initial_conftests hook or config.getvalue().

Example fix

# before
def pytest_addoption(parser):
    parser.addini('myopt', type=list, help='...')

# after
def pytest_addoption(parser):
    parser.addini('myopt', type='linelist', help='...')
Defensive patterns

Strategy: type-guard

Validate before calling

from typing import get_args, Literal
_VALID_TAGS = set(get_args(Literal['string','paths','pathlist','args','linelist','bool','int','float']))
_VALID_TYPES = {str, bool, int, float}
def validate_ini_type(type_: object) -> None:
    if type_ is None or type_ in _VALID_TAGS or type_ in _VALID_TYPES:
        return
    raise ValueError(f'unsupported ini type {type_!r}; use one of {_VALID_TAGS} or { _VALID_TYPES}')

Type guard

from typing import get_args, Literal, get_origin, Union, types
_VALID_TAGS = set(get_args(Literal['string','paths','pathlist','args','linelist','bool','int','float']))
_VALID_PY = {str, bool, int, float}
def is_valid_ini_type(type_: object) -> bool:
    if type_ is None or type_ in _VALID_TAGS or type_ in _VALID_PY:
        return True
    if get_origin(type_) in (Union, types.UnionType):
        return all(is_valid_ini_type(m) for m in type_.__args__)
    if get_origin(type_) is Literal:
        return all(isinstance(c, str) for c in type_.__args__)
    return False

Prevention

When it happens

Trigger: Calling parser.addini('myopt', type='datetime'), type=list, type=dict, type=float-or-str (a custom type), or passing a class that isn't str/bool/int/float. The _ini_type_to_tag lookup in _INI_TYPES fails with KeyError or TypeError (unhashable).

Common situations: Plugin authors passing an unsupported type to addini; migrating a plugin from an older pytest that tolerated looser types; attempting to use a custom callable as the type (which argparse allows but pytest's ini system does not).

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/cf8335de787324a3.json. Report an issue: GitHub.