pytest-dev/pytest · error · ValueError

alias conflicts with existing configuration option

Error message

alias {alias!r} conflicts with existing configuration option

What it means

Raised during addini() when an alias in the aliases= list collides with an existing ini option name already registered in the config. Aliases must not shadow canonical option names. The check `alias in self._inidict` fails.

Solutions

  1. Choose an alias that does not match any existing option name
  2. Remove the conflicting addini call for the old name if it is no longer needed
  3. Check registered options with config._parser._inidict keys before choosing aliases

Example fix

# before
parser.addini('new_opt', type='string', aliases=['old_opt'])
# ... elsewhere
parser.addini('old_opt', type='string')

# after
parser.addini('new_opt', type='string', aliases=['legacy_opt'])
# or remove the old registration
Defensive patterns

Strategy: validation

Validate before calling

def check_alias_no_conflict(parser, aliases: list[str]) -> list[str]:
    conflicts = [a for a in aliases if a in parser._inidict]
    return conflicts
# Usage: conflicts = check_alias_no_conflict(parser, ['old_name'])

Prevention

When it happens

Trigger: Calling parser.addini('new_opt', aliases=['old_opt']) where 'old_opt' was already registered via a prior addini call. The alias string matches a key already in self._inidict.

Common situations: Renaming an option and trying to alias the old name, but the old option is still registered by another plugin. Two plugins registering options with overlapping alias/name sets. Accidental alias collision with a built-in pytest option.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/3cfde3b705d71063. Report an issue: GitHub.

Appendix: source

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

            ini_type = tuple(
                _ini_type_to_member(name, member) for member in get_args(type)
            )
        else:
            ini_type = _ini_type_to_member(name, type)
        if default is NOTSET:
            if isinstance(ini_type, (tuple, _IniLiteral)):
                kind = "union" if isinstance(ini_type, tuple) else "Literal"
                raise ValueError(
                    f"ini option {name!r} has a {kind} type, which has no "
                    "implicit default; pass an explicit `default` to `addini`"
                )
            default = get_ini_default_for_type(ini_type)

        self._inidict[name] = (help, ini_type, default)

        for alias in aliases:
            if alias in self._inidict:
                raise ValueError(
                    f"alias {alias!r} conflicts with existing configuration option"
                )
            if (already := self._ini_aliases.get(alias)) is not None:
                raise ValueError(f"{alias!r} is already an alias of {already!r}")
            self._ini_aliases[alias] = name


def get_ini_default_for_type(type: _IniTypeTag) -> Any:
    """
    Used by addini to get the default value for a given config option type, when
    default is not supplied.
    """
    if type in ("paths", "pathlist", "args", "linelist"):
        return []
    elif type == "bool":
        return False
    elif type == "int":
        return 0

View on GitHub (pinned to 0d6fbdeffa)