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 by SpecifierSet.__and__ (specifiers.py:996) when intersecting two SpecifierSets whose explicit prerelease overrides conflict: one has prereleases=True and the other prereleases=False (both non-None and unequal). The combination logic at lines 991-994 accepts a None on either side or matching values, but explicitly forbids the True-vs-False clash because there is no defensible combined policy.

Solutions

  1. Reconcile the prerelease policy before combining: pass the same prereleases value (or None) to both SpecifierSets, or leave both unset to let autodetect decide.
  2. If you must merge, strip the override by reconstructing one side as SpecifierSet(str(other)) (str drops prereleases) before the & operation.
  3. Decide a single project-wide prerelease policy and apply it at the top level rather than per-SpecifierSet.
  4. Wrap the & in try/except ValueError and surface a clear 'conflicting prerelease policy' error naming both sources.

Example fix

# before
a = SpecifierSet('>=1.0', prereleases=True)
b = SpecifierSet('<2.0', prereleases=False)
combined = a & b  # ValueError

# after - drop the conflicting override, apply one policy
b = SpecifierSet(str(b))  # prereleases=None
combined = a & b  # ok; combined honors prereleases=True
Defensive patterns

Strategy: validation

Validate before calling

from packaging.specifiers import SpecifierSet

def combine(a: SpecifierSet, b: SpecifierSet) -> SpecifierSet:
    # Drop conflicting prerelease overrides by normalizing to string form.
    if a._prereleases is not None and b._prereleases is not None and a._prereleases != b._prereleases:
        b = SpecifierSet(str(b))  # prereleases=None
    return a & b

Try / catch

try:
    combined = a & b
except ValueError:
    # conflicting prerelease policy; pick one explicit policy
    combined = SpecifierSet(str(a) + ',' + str(b), prereleases=True)

Prevention

When it happens

Trigger: SpecifierSet('>=1.0', prereleases=True) & SpecifierSet('<2.0', prereleases=False); building a combined requirement programmatically where one source forces prereleases on and another forces them off; intersecting a tool's resolver settings (prereleases enabled) with a project policy (prereleases disabled).

Common situations: A resolver/aggregator merging constraints from multiple sources (e.g. user flag --pre vs. project requires_python style guards); pinning tools that let callers set prerelease policy per-constraint then combine them; config layers where one layer sets prereleases=True globally and another layer overrides a subset to False.

Related errors


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

Appendix: source

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

        <SpecifierSet('!=1.0.1,!=2.0.1,<=2.0.0,>=1.0.0')>
        """
        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

        # 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 f399c37189)