pypa/pip · error · TypeError

Cannot restore from

Error message

Cannot restore {self.__class__.__name__} from {state!r}

What it means

Node.__setstate__ tries three known pickle formats when restoring during unpickling: the new compact string format (26.2+), the old __slots__ tuple format (<=26.0), and the old __dict__ format (<=25.0). If the state matches none of them, TypeError is raised with the unrecognizable state shown. This is a broader guard than error 265: it catches completely unrecognized state structures rather than just non-string values.

Solutions

  1. Serialize nodes to strings using serialize() and re-parse on load with parse_marker()/parse_requirement()
  2. Version your cache format and invalidate caches on packaging upgrades
  3. Catch TypeError and re-parse from the original source string as a fallback

Example fix

# before
import pickle
marker_node = pickle.loads(pickled_data)  # incompatible format

# after
# Persist the serialized string form, not the Node object:
# stored = marker_node.serialize()  -> "python_version >= '3.8'"
# On load, re-parse:
from packaging._parser import parse_marker
marker_node = parse_marker(stored_string)
Defensive patterns

Strategy: try-catch

Validate before calling

def safe_restore_node(pickled_data, original_source=None):
    import pickle
    try:
        return pickle.loads(pickled_data)
    except TypeError:
        if original_source:
            from packaging._parser import parse_marker
            return parse_marker(original_source)
        raise

Type guard

def is_recognized_node_state(state) -> bool:
    if isinstance(state, str):
        return True
    if isinstance(state, tuple) and len(state) == 2:
        _, d = state
        return isinstance(d, dict) and "value" in d
    if isinstance(state, dict) and "value" in state:
        return True
    return False

Try / catch

try:
    node = pickle.loads(data)
except TypeError as e:
    if "Cannot restore" in str(e):
        from packaging._parser import parse_marker
        node = parse_marker(original_req_string)

Prevention

When it happens

Trigger: Unpickling a Variable, Value, or Op node from a pickle created by a future or incompatible version of packaging that uses a serialization format this version does not understand.

Common situations: Downgrading packaging after pickling nodes with a newer format. Loading cached data from a different packaging fork. Pickle protocol mismatches after environment changes.

Related errors


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

Appendix: source

Thrown at src/pip/_vendor/packaging/_parser.py:57

            )
        self.value = value

    def __setstate__(self, state: object) -> None:
        if isinstance(state, str):
            # New format (26.2+): just the value string.
            self._restore_value(state)
            return
        if isinstance(state, tuple) and len(state) == 2:
            # Old format (packaging <= 26.0, __slots__): (None, {slot: value}).
            _, slot_dict = state
            if isinstance(slot_dict, dict) and "value" in slot_dict:
                self._restore_value(slot_dict["value"])
                return
        if isinstance(state, dict) and "value" in state:
            # Old format (packaging <= 25.0, no __slots__): plain __dict__.
            self._restore_value(state["value"])
            return
        raise TypeError(f"Cannot restore {self.__class__.__name__} from {state!r}")


class Variable(Node):
    __slots__ = ()

    def serialize(self) -> str:
        return str(self)


class Value(Node):
    __slots__ = ()

    def serialize(self) -> str:
        value = str(self)
        if '"' not in value:
            return f'"{value}"'
        if "'" not in value:
            return f"'{value}'"

View on GitHub (pinned to f399c37189)