pytest-dev/pytest · error · ValueError

option dest already used by (this is the option that maps…

Error message

option dest {dest!r} already used by {option.names()!r} (this is the option that maps to dest {dest!r}); pass dest={dest!r} explicitly to share the destination

What it means

Raised by pytest's option parser when a plugin or conftest calls group.addoption() with an option whose argparse-generated destination (dest) collides with another already-registered option. Because the destination is auto-derived from the option strings (e.g. --foo-bar => foo_bar), two differently-named options can map to the same dest. pytest refuses the ambiguity rather than silently overwriting.

Solutions

  1. Pass an explicit dest=... to addoption() so the two options intentionally share (or differentiate) the destination: group.addoption('--foo-bar', dest='foo_bar').
  2. Rename one of the colliding option strings so they no longer map to the same dest.
  3. Audit conftest.py and installed plugins (pytest --trace-config) for the option names reported in the message and remove the duplicate.

Example fix

// before
group.addoption('--foo-bar')
group.addoption('--foo_bar')
// after
group.addoption('--foo-bar')
group.addoption('--foo_bar', dest='foo_bar_alt')
Defensive patterns

Strategy: validation

Validate before calling

from argparse import Namespace

def safe_addoption(group, *opts, **attrs):
    from _pytest.config.argparsing import _get_argparse_dest
    if 'dest' not in attrs and group.parser:
        dest = _get_argparse_dest(opts)
        for g in group.parser._groups:
            for o in g.options:
                if o.dest == dest:
                    raise SystemExit(f'pre-conflict: dest {dest!r} used by {o.names()!r}')
    group.addoption(*opts, **attrs)

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Calling group.addoption('--foo-bar') after '--foo_bar' was already added (both yield dest 'foo_bar'); or registering '--foo' in two groups where argparse's internal dest dedup kicks in. The check runs only when 'dest' is not explicitly set in attrs and the group is attached to a parser.

Common situations: Two plugins registering options with names that normalize to the same dest (hyphens vs underscores); upgrading a plugin that now adds an option colliding with your conftest.py custom option; copy-pasting an addoption across conftest files.

Related errors


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

Appendix: source

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

        :param opts:
            Option names, can be short or long options.
            Note that lower-case short options (e.g. `-x`) are reserved.
        :param attrs:
            Same attributes as the argparse library's :meth:`add_argument()
            <argparse.ArgumentParser.add_argument>` function accepts.
        """
        conflict = set(opts).intersection(
            name for opt in self.options for name in opt.names()
        )
        if conflict:
            raise ValueError(f"option names {conflict} already added")

        if self.parser and "dest" not in attrs:
            dest = _get_argparse_dest(opts)
            for group in self.parser._groups:
                for option in group.options:
                    if option.dest == dest:
                        raise ValueError(
                            f"option dest {dest!r} already used by "
                            f"{option.names()!r} (this is the option that maps to "
                            f"dest {dest!r}); pass dest={dest!r} explicitly "
                            "to share the destination"
                        )
        self._addoption_inner(opts, attrs, allow_reserved=False)

    def _addoption(self, *opts: str, **attrs: Any) -> None:
        """Like addoption(), but also allows registering short lower case options (e.g. -x),
        which are reserved for pytest core."""
        self._addoption_inner(opts, attrs, allow_reserved=True)

    def _addoption_inner(
        self, opts: tuple[str, ...], attrs: dict[str, Any], allow_reserved: bool
    ) -> None:
        if not allow_reserved:
            for opt in opts:
                if len(opt) >= 2 and opt[0] == "-" and opt[1].islower():

View on GitHub (pinned to 0d6fbdeffa)