pytest-dev/pytest · error · ValueError

lowercase short options are reserved

Error message

lowercase short options are reserved

What it means

Raised by OptionGroup.addoption() (the public API) when a registered option uses a lowercase single-character short form like '-x'. Lowercase short options are reserved for pytest's own core options; plugins and conftests must use uppercase short options (e.g. '-X') or long options only. The internal _addoption path bypasses this check for core use.

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 98b357f69e)

Solutions

  1. Use an uppercase short option: addoption('-X', '--extra').
  2. Drop the short form entirely and keep only the long option: addoption('--extra').
  3. Reserve any genuinely needed lowercase short option by coordinating with pytest core.

Example fix

# before
group.addoption('-x', '--extra', help='...')

# after
group.addoption('-X', '--extra', help='...')
Defensive patterns

Strategy: validation

Validate before calling

def validate_short_option(opt: str) -> None:
    if len(opt) >= 2 and opt[0] == '-' and opt[1].islower():
        raise ValueError(f'lowercase short option {opt!r} is reserved')

Type guard

def is_reserved_lowercase_short(opt: str) -> bool:
    return len(opt) >= 2 and opt[0] == '-' and opt[1].islower()

Prevention

When it happens

Trigger: A conftest.py or plugin calling group.addoption('-x', '--extra', ...) where '-x' is a lowercase short option. The check at line 480-483 flags any opt of length >= 2 starting with '-' whose second char is lowercase.

Common situations: Plugin authors unaware of the reservation policy; porting an argparse-based tool's options into pytest and keeping lowercase shorts; accidental lowercase letters in short option strings.

Related errors


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