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
- Pass an explicit dest=... to addoption() so the two options intentionally share (or differentiate) the destination: group.addoption('--foo-bar', dest='foo_bar').
- Rename one of the colliding option strings so they no longer map to the same dest.
- 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
- Always pass dest=... explicitly when registering options in plugins to make destinations unambiguous.
- Run pytest --trace-config after registering options to spot duplicates early.
- Namespace your plugin options with a prefix to avoid accidental dest collisions.
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
- lowercase short options are reserved
- Blocking conftest files using -p is not supported: -p no
- must be a directory, given
- must be a filename, given
- Plugins may be specified as a sequence or a ','-separated…
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)