nodejs/node · error · ValueError

Cannot combine SpecifierSets with True and False prerelease

Error message

Cannot combine SpecifierSets with True and False prerelease overrides.

What it means

ValueError raised by SpecifierSet.__and__ (the & operator) when combining two SpecifierSets whose explicit prerelease overrides conflict - one has _prereleases True and the other False. The combine logic only resolves None-vs-value and equal-value cases; a True-vs-False contradiction cannot be merged deterministically, so it refuses.

Source

Thrown at tools/gyp/pylib/packaging/specifiers.py:828

        >>> SpecifierSet(">=1.0.0,!=1.0.1") & SpecifierSet('<=2.0.0,!=2.0.1')
        <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 = frozenset(self._specs | other._specs)

        if self._prereleases is None and other._prereleases is not None:
            specifier._prereleases = other._prereleases
        elif self._prereleases is not None and other._prereleases is None:
            specifier._prereleases = self._prereleases
        elif self._prereleases == other._prereleases:
            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

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Normalize both operands to the same prereleases value (or leave them as None for autodetection) before combining.
  2. Compute the intersection of one operand and then set .prereleases afterwards on the result.
  3. Catch ValueError and report which two SpecifierSets conflict so the user can reconcile them.

Example fix

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

# after
a = SpecifierSet('>=1.0')
b = SpecifierSet('>=2.0')
combined = a & b
combined.prereleases = True
Defensive patterns

Strategy: validation

Validate before calling

def can_combine(a: SpecifierSet, b: SpecifierSet) -> bool:
    if a._prereleases is None or b._prereleases is None:
        return True
    return a._prereleases == b._prereleases

Try / catch

try:
    combined = a & b
except ValueError as e:
    if 'prerelease' in str(e):
        b.prereleases = a.prereleases
        combined = a & b

Prevention

When it happens

Trigger: Computing SpecifierSet('>=1.0', prereleases=True) & SpecifierSet('>=1.0', prereleases=False) - i.e. intersecting two sets after one had .prereleases (or the prereleases= kwarg) set to True and the other to False.

Common situations: Merging requirement specifiers coming from different sources (e.g. user override vs. default config) where one side explicitly enables prereleases and the other explicitly disables them.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/5a042f4fa59cf675. Report an issue: GitHub.