pytest-dev/pytest · error · ValueError

{alias!r} is already an alias of {already!r}

Error message

{alias!r} is already an alias of {already!r}

What it means

Raised by Parser.addini() when an alias in aliases= is already mapped to a different canonical option. Each alias can only point to one option; attempting to reuse it for a second option is rejected at registration time.

Source

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

            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
    elif type == "float":
        return 0.0
    else:
        return ""

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Use a unique alias for each option, namespaced by plugin name if needed.
  2. Remove the duplicate alias registration from one of the addini calls.
  3. Audit all plugins' addini aliases to build a non-overlapping set.

Example fix

# before
parser.addini('opt1', aliases=['v'], help='...')
parser.addini('opt2', aliases=['v'], help='...')  # already taken

# after
parser.addini('opt1', aliases=['v'], help='...')
parser.addini('opt2', aliases=['v2'], help='...')
Defensive patterns

Strategy: validation

Validate before calling

def check_alias_unique(existing_aliases: dict, alias: str) -> None:
    if alias in existing_aliases:
        raise ValueError(f'{alias!r} is already an alias of {existing_aliases[alias]!r}')

Prevention

When it happens

Trigger: parser.addini('opt1', aliases=['x']) followed by parser.addini('opt2', aliases=['x']). The check at line 363 finds self._ini_aliases['x'] already set to 'opt1'.

Common situations: Multiple plugins independently choosing the same short alias; consolidating options and forgetting an alias was already taken; generic alias names like 'verbose' clashing across plugins.

Related errors


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