pypa/pip · error · TypeError

Cannot restore Requirement from

Error message

Cannot restore Requirement from {state!r}

What it means

TypeError raised by Requirement.__setstate__ during unpickling when the saved state does not match any recognized pickle format. packaging recognizes three shapes (26.2 string, 26.3 (string, prereleases) tuple, legacy __dict__); anything else means the pickle was not produced by a packaging Requirement, so restoration is refused to avoid silently constructing a wrong object.

Solutions

  1. Verify the object in the pickle is actually a packaging Requirement; if not, reconstruct it from its string form instead.
  2. If migrating from an old private format, read it with the code that wrote it and re-serialize as a Requirement string (str(req)), then re-parse: Requirement(req_string).
  3. Do not fabricate __getstate__ tuples manually; if you must, use the 26.3 shape (requirement_string, prereleases_bool_or_None).
  4. Regenerate the pickle from a current packaging version to get a forward-compatible format.

Example fix

# before: pickle produced by an incompatible serializer
req = pickle.loads(blob)  # TypeError: Cannot restore Requirement from (1, 0, 'foo')

# after: store/restore the canonical string form
import pickle
from packaging.requirements import Requirement
blob = pickle.dumps(str(Requirement('foo>=1.0')))
req = Requirement(pickle.loads(blob))
Defensive patterns

Strategy: try-catch

Validate before calling

from packaging.requirements import Requirement

def looks_like_requirement_state(state) -> bool:
    if isinstance(state, str):
        return True
    if (isinstance(state, tuple) and len(state) == 2
            and isinstance(state[0], str)
            and (state[1] is None or isinstance(state[1], bool))):
        return True
    if isinstance(state, dict) and state.keys() >= set(Requirement.__slots__):
        return True
    return False

assert looks_like_requirement_state(loaded_state), repr(loaded_state)

Type guard

null

Try / catch

import pickle
from packaging.requirements import Requirement
try:
    req = pickle.loads(blob)
except TypeError as e:
    if 'Cannot restore Requirement' in str(e):
        # not a real Requirement pickle; reconstruct from its string form instead
        raise

Prevention

When it happens

Trigger: Unpickling (pickle.loads) a bytes stream that claims to be a Requirement but whose __getstate__ payload is, e.g., a 3-tuple, an int, a list, or a dict missing some __slots__ keys. Also if a custom serializer wrote a non-conforming state and you feed it to Requirement.__setstate__.

Common situations: Loading a pickle written by a different/older library version that used a private format; a corrupted or hand-crafted pickle; a migration that round-trips Requirement through an intermediate format that lost the prereleases field.

Related errors


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

Appendix: source

Thrown at src/pip/_vendor/packaging/requirements.py:144

        if isinstance(state, str):
            # Format (26.2): just the requirement string.
            requirement_string: str = state
            prereleases: bool | None = None
        elif (
            isinstance(state, tuple)
            and len(state) == 2
            and isinstance(state[0], str)
            and (state[1] is None or isinstance(state[1], bool))
        ):
            # New format (26.3+): (requirement string, specifier prereleases).
            requirement_string, prereleases = state
        elif isinstance(state, dict) and state.keys() >= set(self.__slots__):
            # Old format (packaging <= 26.1, no __slots__): plain __dict__.
            for key in self.__slots__:
                setattr(self, key, state[key])
            return
        else:
            raise TypeError(f"Cannot restore Requirement from {state!r}")

        try:
            tmp = Requirement(requirement_string)
        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.specifier._prereleases = prereleases
        self.marker = tmp.marker

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