pytest-dev/pytest · error · ValueError
lowercase short options are reserved
Error message
lowercase short options are reserved
What it means
pytest reserves single-letter lowercase short options (e.g. -x, -q) for its own core. When a plugin author registers an option via the public group.addoption() (not the internal _addoption) and one of the option strings is a lowercase short flag like '-x', pytest rejects it. This keeps the short namespace stable for pytest itself.
Solutions
- Use an uppercase short option (e.g. '-X') instead, since uppercase shorts are not reserved.
- Use only a long option (e.g. '--myflag') and drop the short form entirely.
- If you genuinely need a core short option, you cannot register it; rely on the existing core behavior instead.
Example fix
// before
group.addoption('-x', '--my-x-flag', action='store_true')
// after
group.addoption('-X', '--my-x-flag', action='store_true') Defensive patterns
Strategy: validation
Validate before calling
def is_reserved_short(opt: str) -> bool:
return len(opt) >= 2 and opt[0] == '-' and opt[1].islower()
for o in opts:
assert not is_reserved_short(o), f'{o!r} is a reserved lowercase short option' Type guard
null
Try / catch
null
Prevention
- Prefer long option names ('--myflag') for plugin/conftest options.
- If a short flag is needed, use uppercase ('-M').
- Reserve lowercase shorts for pytest core only.
When it happens
Trigger: Calling group.addoption('-x', ...) (lowercase single letter) from a conftest or plugin. Only paths through addoption()/allow_reserved=False enforce this; pytest core uses _addoption which sets allow_reserved=True.
Common situations: Plugin author picking '-c' or '-f' for their flag without realizing it collides with reserved core options; a conftest trying to add a convenience short flag.
Related errors
- option dest already used by (this is the option that maps…
- Blocking conftest files using -p is not supported: -p no
- fixture ' ' not found
- must be a directory, given
- must be a filename, given
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/c2c50d5b5c13cc5d.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/config/argparsing.py:483
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():
raise ValueError("lowercase short options are reserved")
action = self._arggroup.add_argument(*opts, **attrs)
option = Argument(action)
self.options.append(option)
if self.parser:
for name in option.names():
self.parser._opt2dest[name] = option.dest
self.parser.processoption(option)
class PytestArgumentParser(argparse.ArgumentParser):
def __init__(
self,
usage: str | None,
extra_info: dict[str, str],
*,
prog: str | None = None,
) -> None:View on GitHub (pinned to 0d6fbdeffa)