pypa/pip · error · TypeError
Cannot restore {self.__class__.__name__} from {state!r}
Error message
Cannot restore {self.__class__.__name__} from {state!r} What it means
Raised by `Node.__setstate__` when the persisted state is neither a plain string (new 26.2+ format), nor the old `(None, {slot: value})` tuple (packaging ≤26.0 with `__slots__`), nor a dict with a `value` key (packaging ≤25.0). It is a backwards-compatibility guard so that pickles produced by older packaging can still be loaded, while genuinely unrecognized formats are rejected.
Source
Thrown at src/pip/_vendor/packaging/_parser.py:56
)
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:
return f'"{self}"'
class Op(Node):
__slots__ = ()View on GitHub (pinned to d7d0d0a394)
Solutions
- Clear the stale cache (pip cache purge, remove `__pycache__`/wheel cache dirs) so objects are re-parsed from source
- Pin matching `packaging` versions across the environments exchanging pickles
- Serialize the specifier/marker as a string and re-parse via `Specifier()`/`Marker()` on load instead of pickling AST nodes
Example fix
// before
obj = pickle.load(open('cache.pkl','rb')) # raises
// after
# do not pickle AST nodes; store the source string
import pickle
from packaging.specifiers import Specifier
src = '>=1.0' # stored in cache instead
obj = Specifier(src) Defensive patterns
Strategy: try-catch
Validate before calling
def is_recognized_node_state(state) -> bool:
if isinstance(state, str):
return True
if isinstance(state, tuple) and len(state) == 2:
_, sd = state
return isinstance(sd, dict) and 'value' in sd
if isinstance(state, dict) and 'value' in state:
return True
return False Type guard
from typing import Any
def is_loadable_node_state(state: Any) -> bool:
return (
isinstance(state, str)
or (isinstance(state, dict) and 'value' in state)
or (isinstance(state, tuple) and len(state) == 2
and isinstance(state[1], dict) and 'value' in state[1])
) Try / catch
try:
obj = pickle.load(fh)
except TypeError as e:
if 'Cannot restore' in str(e):
log.warning('stale pickle cache, clearing')
os.remove(cache_path)
obj = Specifier(src_string) # re-parse
else:
raise Prevention
- Cache specifier/marker source strings, not AST node pickles
- Run `pip cache purge` after upgrading packaging
- Version-stamp cache files and invalidate on packaging version mismatch
When it happens
Trigger: Unpickling a `Specifier`/`Marker` AST node whose pickle was produced by a much older or future packaging version; a pickle file shared across machines with mismatched packaging versions; a hand-constructed state tuple of the wrong shape.
Common situations: Cached build artifacts (pip's wheel cache, build backend caches) persisted on disk and reloaded after a packaging upgrade; copying pickled objects between Python environments; CI using a stale cache volume.
Related errors
- Cannot restore {self.__class__.__name__} value from {value!r
- Cannot restore Requirement from {state!r}
- Cannot restore Specifier from {state!r}
- Cannot restore SpecifierSet from {state!r}
- Cannot restore Tag from {state!r}
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/77f530b492ebe1bc.json.
Report an issue: GitHub.