pypa/pip · error · TypeError
expected a SpecifierSet
Error message
expected a SpecifierSet
What it means
Raised as TypeError by SpecifierSet._check_relation_operand (specifiers.py:1145), the guard invoked by is_subset/is_superset/is_disjoint/is_proper_subset relations. If the other operand is not an instance of SpecifierSet the method raises immediately before any range comparison. Passing a raw string, a Specifier, a list, or None all trigger it.
Source
Thrown at src/pip/_vendor/packaging/specifiers.py:1145
def to_range(self) -> ranges.VersionRange:
"""Return the :class:`~packaging.ranges.VersionRange` this set accepts.
An empty set yields the full range; an unsatisfiable set yields the
empty range. ``===`` specifiers contribute literal-string admission.
>>> SpecifierSet(">=1.0,<2.0").to_range()
<VersionRange '[1.0, 2.0.dev0)'>
.. versionadded:: 26.3
"""
from .ranges import VersionRange # noqa: PLC0415
return VersionRange._from_specifier_set(self)
def _check_relation_operand(self, other: object) -> None:
if not isinstance(other, SpecifierSet):
raise TypeError("expected a SpecifierSet")
if self._has_arbitrary or other._has_arbitrary:
raise ValueError("set relations do not support === specifiers")
def is_subset(self, other: SpecifierSet) -> bool:
"""Return whether every version matching this set also matches other.
:raises ValueError:
If either set uses ``===`` specifiers, or the two sets were
given different ``prereleases`` arguments (unset on one side
counts as different).
:raises TypeError:
If other is not a :class:`SpecifierSet`.
>>> SpecifierSet(">=3.12,<3.13").is_subset(SpecifierSet(">=3.12"))
True
>>> SpecifierSet(">=3.12").is_subset(SpecifierSet(">=3.12,<3.13"))
False
View on GitHub (pinned to f399c37189)
Solutions
- Wrap the operand: other = SpecifierSet(other) if isinstance(other, str) else other before calling the relation.
- Ensure your helper always passes a SpecifierSet instance; convert at the boundary.
- If other is already a single Specifier, wrap it: SpecifierSet(str(specifier)).
- Add a type guard / isinstance check and raise a clearer domain-specific error before the call.
Example fix
# before
ss = SpecifierSet('>=3.12')
ss.is_subset('>=3.12') # TypeError: expected a SpecifierSet
# after
from packaging.specifiers import SpecifierSet
other = SpecifierSet('>=3.12') if isinstance(other, str) else other
ss.is_subset(other) Defensive patterns
Strategy: type-guard
Validate before calling
from packaging.specifiers import SpecifierSet, Specifier
def to_specifierset(v) -> SpecifierSet:
if isinstance(v, str):
return SpecifierSet(v)
if isinstance(v, Specifier):
return SpecifierSet(str(v))
if isinstance(v, SpecifierSet):
return v
raise TypeError(f'expected SpecifierSet/str/Specifier, got {type(v)!r}') Type guard
from packaging.specifiers import SpecifierSet
def is_specifierset(v) -> bool:
return isinstance(v, SpecifierSet) Try / catch
try:
a.is_subset(other)
except TypeError:
other = to_specifierset(other)
return a.is_subset(other) Prevention
- Always convert specifier-like inputs to SpecifierSet at the boundary.
- Type-annotate relation helper params as SpecifierSet.
- Unit-test the relation API with str, Specifier, and SpecifierSet inputs.
When it happens
Trigger: SpecifierSet('>=3.12').is_subset('>=3.12') (passing a str instead of SpecifierSet); .is_superset(some_specifier) (a Specifier, not a set); .is_subset(None); passing a list of spec strings.
Common situations: Calling the new 26.3 set-relation API with values read from config (strings) without wrapping them; mixing Specifier and SpecifierSet in a comparison helper; type-mismatched helper functions that accept 'specifier-like' input.
Related errors
- set relations do not support === specifiers
- expected VersionRange, got {type(other).__name__}
- VersionRange.contains() expected str or Version, got {type(i
- Invalid specifier: {spec!r}
- Cannot restore Specifier from {state!r}
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/03718b22388715df.
Report an issue: GitHub.