{"id":"04a60174c1336e08","repo":"pytest-dev/pytest","slug":"invalid-type-for-ini-option-name-r-literal-choi","errorCode":null,"errorMessage":"invalid type for ini option {name!r}: Literal choices must be strings, got {choices!r}","messagePattern":"invalid type for ini option (.+?): Literal choices must be strings, got (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/config/argparsing.py","lineNumber":87,"sourceCode":"def _ini_type_to_tag(name: str, type_: object) -> _IniTypeTag:\n    \"\"\"Normalize one member of an `addini(type=...)` argument to a string tag.\"\"\"\n    try:\n        return _INI_TYPES[type_]\n    except (KeyError, TypeError):  # TypeError: unhashable type_\n        raise ValueError(\n            f\"invalid type for ini option {name!r}: {type_!r} (expected one of \"\n            f\"{', '.join(repr(tag) for tag in get_args(_IniTypeTag))}, one of \"\n            \"the types str, bool, int, float, a union of these types such as \"\n            \"`int | str`, or a `Literal` of strings)\"\n        ) from None\n\n\ndef _ini_type_to_member(name: str, type_: object) -> _IniTypeTag | _IniLiteral:\n    \"\"\"Normalize one member of an `addini(type=...)` argument.\"\"\"\n    if get_origin(type_) is Literal:\n        choices = get_args(type_)\n        if not all(isinstance(choice, str) for choice in choices):\n            raise ValueError(\n                f\"invalid type for ini option {name!r}: Literal choices \"\n                f\"must be strings, got {choices!r}\"\n            )\n        return _IniLiteral(choices)\n    return _ini_type_to_tag(name, type_)\n\n\ndef _ini_type_repr(type: IniType) -> str:\n    \"\"\"Render an ini option type for --help output and error messages.\"\"\"\n    if isinstance(type, _IniLiteral):\n        return \" | \".join(repr(choice) for choice in type.choices)\n    if isinstance(type, tuple):\n        return \" | \".join(_ini_type_repr(member) for member in type)\n    return type\n\n\ndef _get_argparse_dest(opts: Sequence[str]) -> str:\n    long_opts = [opt for opt in opts if opt.startswith(\"--\")]","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/config/argparsing.py#L69-L105","documentation":"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.","triggerScenarios":"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).","commonSituations":"Plugin authors wanting an int/bool enum via Literal; mixing string and numeric literal values expecting automatic coercion.","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()."],"exampleFix":"# before\nparser.addini('level', type=Literal[1, 2, 3], help='verbosity')\n\n# after\nparser.addini('level', type=Literal['1', '2', '3'], help='verbosity')","handlingStrategy":"type-guard","validationCode":"from typing import get_origin, get_args, Literal\ndef validate_literal_choices(type_: object) -> None:\n    if get_origin(type_) is Literal:\n        choices = get_args(type_)\n        bad = [c for c in choices if not isinstance(c, str)]\n        if bad:\n            raise TypeError(f'Literal choices must be strings, got {bad!r}')","typeGuard":"from typing import get_origin, get_args, Literal\ndef is_string_literal(type_: object) -> bool:\n    return get_origin(type_) is Literal and all(isinstance(c, str) for c in get_args(type_))","tryCatchPattern":null,"preventionTips":["Keep Literal choices string-only; coerce numerics in your reader code.","Add a plugin-load test exercising each addini call."],"tags":["pytest","plugin","config","addini","literal","type-check"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}