pypa/pip · error · TypeError
Cannot restore Requirement from {state!r}
Error message
Cannot restore Requirement from {state!r} What it means
Raised as TypeError (requirements.py:97) inside Requirement.__setstate__ when unpickling a Requirement whose stored state is the new-format string (packaging >=26.2) but that string no longer parses via Requirement(). The constructor failure (InvalidRequirement) is re-raised as this TypeError so the pickle layer reports an unreadable pickle.
Source
Thrown at src/pip/_vendor/packaging/requirements.py:97
yield f" @ {self.url}"
if self.marker:
yield " "
if self.marker:
yield f"; {self.marker}"
def __getstate__(self) -> str:
# Return the requirement string for compactness and stability.
# Re-parsed on load to reconstruct all fields.
return str(self)
def __setstate__(self, state: object) -> None:
if isinstance(state, str):
# New format (26.2+): just the requirement string.
try:
tmp = Requirement(state)
except InvalidRequirement as exc:
raise TypeError(f"Cannot restore Requirement from {state!r}") from exc
self.name = tmp.name
self.url = tmp.url
self.extras = tmp.extras
self.specifier = tmp.specifier
self.marker = tmp.marker
return
if isinstance(state, dict):
# Old format (packaging <= 26.1, no __slots__): plain __dict__.
self.__dict__.update(state)
return
raise TypeError(f"Cannot restore Requirement from {state!r}")
def __str__(self) -> str:
return "".join(self._iter_parts(self.name))
def __repr__(self) -> str:
return f"<{self.__class__.__name__}({str(self)!r})>"
View on GitHub (pinned to d7d0d0a394)
Solutions
- Discard the stale pickle/cache and rebuild the Requirement from the original requirement string.
- Pin both producer and consumer to the same packaging version.
- Catch TypeError around pickle.load and fall back to re-parsing Requirement(str(...)) from a trusted source.
Example fix
# before
req = pickle.load(open("cache.pkl", "rb")) # raises TypeError
# after
try:
req = pickle.load(open("cache.pkl", "rb"))
except TypeError:
from pip._vendor.packaging.requirements import Requirement
req = Requirement(open("req.txt").read().strip()) Defensive patterns
Strategy: try-catch
Validate before calling
from pip._vendor.packaging.requirements import Requirement, InvalidRequirement
def requirement_string_restorable(req_string):
try:
Requirement(req_string)
return True
except InvalidRequirement:
return False Type guard
null
Try / catch
import pickle
from pip._vendor.packaging.requirements import Requirement
try:
obj = pickle.load(open(path, 'rb'))
except TypeError as e:
if 'Cannot restore Requirement' in str(e):
obj = Requirement(trusted_requirement_string()) Prevention
- Do not persist Requirement objects as pickles across packaging upgrades; store str(req) instead.
- Pin producer and consumer packaging to the same version when exchanging pickles.
When it happens
Trigger: pickle.load() on a pickle produced by packaging >=26.2 where the requirement string has since become invalid (parser regression, manual edit, cross-vendor parser differences). The new __getstate__ returns str(self), so any corruption of that string trips this path.
Common situations: Loading a cached pickle (e.g. a resolved requirements cache) after upgrading packaging in a way that tightened the PEP 508 grammar. Cross-process handoff where the producer and consumer disagree on requirement-string validity.
Related errors
- Cannot restore {self.__class__.__name__} value from {value!r
- Cannot restore Specifier from {state!r}
- Cannot restore SpecifierSet from {state!r}
- Cannot restore Tag from {state!r}
- {editable_req} is not a valid editable requirement. It shoul
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/2887aff69d536d26.json.
Report an issue: GitHub.