pypa/pip · error · ValueError

Cannot combine SpecifierSets with True and False prerelease

Error message

Cannot combine SpecifierSets with True and False prerelease overrides.

What it means

Raised as ValueError (specifiers.py:1568) by SpecifierSet.__and__ (the '&' operator) when combining two SpecifierSets whose _prereleases overrides are explicitly and contradictorily set (one True, one False). The combine logic picks the common value, or the non-None value, but refuses to silently pick between two opposing explicit overrides.

Source

Thrown at src/pip/_vendor/packaging/specifiers.py:1568

        """
        if isinstance(other, str):
            other = SpecifierSet(other)
        elif not isinstance(other, SpecifierSet):
            return NotImplemented

        specifier = SpecifierSet()
        specifier._specs = self._specs + other._specs
        specifier._canonicalized = len(specifier._specs) <= 1
        specifier._has_arbitrary = self._has_arbitrary or other._has_arbitrary
        specifier._resolved_ops = None

        # Combine prerelease settings: use common or non-None value
        if self._prereleases is None or self._prereleases == other._prereleases:
            specifier._prereleases = other._prereleases
        elif other._prereleases is None:
            specifier._prereleases = self._prereleases
        else:
            raise ValueError(
                "Cannot combine SpecifierSets with True and False prerelease overrides."
            )

        return specifier

    def __eq__(self, other: object) -> bool:
        """Whether or not the two SpecifierSet-like objects are equal.

        :param other: The other object to check against.

        The value of :attr:`prereleases` is ignored.

        >>> SpecifierSet(">=1.0.0,!=1.0.1") == SpecifierSet(">=1.0.0,!=1.0.1")
        True
        >>> (SpecifierSet(">=1.0.0,!=1.0.1", prereleases=False) ==
        ...  SpecifierSet(">=1.0.0,!=1.0.1", prereleases=True))
        True
        >>> SpecifierSet(">=1.0.0,!=1.0.1") == ">=1.0.0,!=1.0.1"

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Make the two operand prereleases overrides agree: set both to None, both to True, or both to False before combining.
  2. Reconstruct one operand without the prereleases kwarg so its _prereleases is None and the other wins.
  3. Decide on a single prereleases policy upstream and apply it consistently to every SpecifierSet in the intersection.

Example fix

# before
from pip._vendor.packaging.specifiers import SpecifierSet
a = SpecifierSet(">=1.0", prereleases=True)
b = SpecifierSet("<=2.0", prereleases=False)
combined = a & b  # ValueError

# after
a = SpecifierSet(">=1.0", prereleases=True)
b = SpecifierSet("<=2.0", prereleases=True)
combined = a & b
Defensive patterns

Strategy: validation

Validate before calling

def combinable_prereleases(a: 'SpecifierSet', b: 'SpecifierSet') -> bool:
    pa, pb = a._prereleases, b._prereleases
    return pa is None or pb is None or pa == pb

Type guard

null

Try / catch

from pip._vendor.packaging.specifiers import SpecifierSet
try:
    combined = a & b
except ValueError as e:
    if 'prerelease overrides' in str(e):
        b = SpecifierSet(str(b), prereleases=a._prereleases)
        combined = a & b

Prevention

When it happens

Trigger: SpecifierSet('>=1.0', prereleases=True) & SpecifierSet('<=2.0', prereleases=False). Also when intersecting via the & operator on two sets each constructed with an explicit prereleases kwarg of opposite bool values.

Common situations: Resolver code that builds specifiers with hardcoded prereleases flags then intersects them. Mixing user-supplied (prereleases=False) and dependency-declared (prereleases=True) specifier sets in one resolution.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/fde6d53ca2d96972.json. Report an issue: GitHub.