{"id":"9d8eca5238391071","repo":"pytest-dev/pytest","slug":"self-inipath-config-option-name-expects-one","errorCode":null,"errorMessage":"{self.inipath}: config option '{name}' expects one of {_ini_type_repr(type)}, got {builtins.type(value).__name__}: {value!r}","messagePattern":"(.+?): config option '(.+?)' expects one of (.+?), got (.+?): (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/config/__init__.py","lineNumber":1843,"sourceCode":"        mode = selected.mode\n\n        # An invalid value is a user error, raised as UsageError so that it is\n        # reported as a short message rather than an internal error traceback.\n        try:\n            if not isinstance(type, tuple):\n                return self._getini_value(\n                    mode, name, canonical_name, type, value, default\n                )\n\n            # Union: try each member; the first one that accepts the value wins.\n            for member in type:\n                try:\n                    return self._getini_value(\n                        mode, name, canonical_name, member, value, default\n                    )\n                except (TypeError, ValueError):\n                    pass\n            raise TypeError(\n                f\"{self.inipath}: config option '{name}' expects one of \"\n                f\"{_ini_type_repr(type)}, got {builtins.type(value).__name__}: {value!r}\"\n            )\n        except (TypeError, ValueError) as e:\n            raise UsageError(str(e)) from e\n\n    def _getini_value(\n        self,\n        mode: Literal[\"ini\", \"toml\"],\n        name: str,\n        canonical_name: str,\n        type: str | _IniLiteral,\n        value: object,\n        default: Any,\n    ):\n        \"\"\"Convert a config value, read in the given mode, to the option's type.\"\"\"\n        if isinstance(type, _IniLiteral):\n            # A Literal value is a plain string checked against the registered","sourceCodeStart":1825,"sourceCodeEnd":1861,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/config/__init__.py#L1825-L1861","documentation":"Raised by Config._getini (config/__init__.py:1843-1846) for a union (tuple) ini type when the supplied value could not be coerced/parsed by ANY member type. Each member is tried in turn inside _getini_value; if all raise TypeError/ValueError, this aggregate TypeError is raised and then wrapped as UsageError at line 1847-1848.","triggerScenarios":"Registering addini with type=(\"bool\",\"string\") (or a Literal/union) and providing a value that matches none of the members — e.g. a TOML integer for an option typed as a string-or-bool union. Triggered on getini or any path that reads ini.","commonSituations":"Misconfigured pyproject.toml [tool.pytest.ini_options] supplying a native type incompatible with every member of a union option; combining string-only and bool-only types and feeding an int; migration from .ini (always str) to .toml exposing previously-hidden type mismatches.","solutions":["Read the error: it lists the expected types and the actual type/value — align the config value with one of them.","If the value should be a string, quote it in TOML (my_opt = \"value\").","If the value should be a bool, use true/false in TOML or yes/no in INI.","Adjust the registered union in addini to include the type you actually need."],"exampleFix":"# before (pyproject.toml)\n[tool.pytest.ini_options]\naddopts = 3   # option typed (bool|string)\n\n# after\naddopts = \"-x\"   # a string","handlingStrategy":"validation","validationCode":"def check_union(value, types):\n    accepted = False\n    for t in types:\n        try:\n            if t == 'bool':\n                accepted = isinstance(value, bool)\n            elif t == 'string':\n                accepted = isinstance(value, str)\n            elif t == 'int':\n                accepted = isinstance(value, int) and not isinstance(value, bool)\n            if accepted:\n                return\n        except Exception:\n            pass\n    raise ValueError(f'value {value!r} matches none of {types}')","typeGuard":"def matches_union_member(value, member: str) -> bool:\n    if member == 'bool': return isinstance(value, bool)\n    if member == 'int':  return isinstance(value, int) and not isinstance(value, bool)\n    if member == 'float': return isinstance(value, (int, float)) and not isinstance(value, bool)\n    if member == 'string': return isinstance(value, str)\n    return False","tryCatchPattern":"try:\n    config.getini(name)\nexcept Exception as e:  # UsageError wrapping TypeError\n    # align the config value with one of the union members, then retry\n    fix_and_reload(name)","preventionTips":["When migrating ini->toml, re-check types for every union option.","Quote strings, use native bool/int in TOML to match member types.","Keep union types narrow in addini registrations."],"tags":["config","ini","toml","union-type","type-mismatch","pytest"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}