pypa/pip · error · TypeError
Cannot restore Version from {state!r}
Error message
Cannot restore Version from {state!r} What it means
Raised by Version.__setstate__ when restoring (unpickling/copying) a Version object whose serialized state does not match any of the three supported historical layouts: a 6-tuple (packaging 26.2+), a 2-tuple of (None, slot-dict) (packaging 26.0-26.1), or a plain dict with a '_version' NamedTuple (packaging <=25.x). The library supports cross-version migration of its pickle format, but bails out with a TypeError when the state is structurally unrecognizable. This protects callers from silently constructing a Version with garbage fields.
Source
Thrown at src/pip/_vendor/packaging/version.py:819
self._pre = slot_dict.get("_pre")
self._post = slot_dict.get("_post")
self._dev = slot_dict.get("_dev")
self._local = slot_dict.get("_local")
return
if isinstance(state, dict):
# Old format (packaging <= 25.x, no __slots__): state is a plain
# dict with "_version" (_Version NamedTuple) and "_key" entries.
version_nt = state.get("_version")
if version_nt is not None:
self._epoch = version_nt.epoch
self._release = version_nt.release
self._pre = version_nt.pre
self._post = version_nt.post
self._dev = version_nt.dev
self._local = version_nt.local
return
raise TypeError(f"Cannot restore Version from {state!r}")
@property
@_deprecated("Version._version is private and will be removed soon")
def _version(self) -> _Version:
return _Version(
self._epoch, self._release, self._dev, self._pre, self._post, self._local
)
@_version.setter
@_deprecated("Version._version is private and will be removed soon")
def _version(self, value: _Version) -> None:
self._epoch = value.epoch
self._release = value.release
self._dev = value.dev
self._pre = value.pre
self._post = value.post
self._local = value.local
self._key_cache = NoneView on GitHub (pinned to d7d0d0a394)
Solutions
- Re-create the Version object from its string form on the consuming side: pickle/serialize the str(version) and re-parse with Version(str_version) instead of pickling the object itself.
- Align the packaging/pip version on both the producing and consuming sides so the pickle state format matches (the three supported formats span packaging <=25.x, 26.0-26.1, and 26.2+).
- If you control the state object, ensure it is a 6-tuple (epoch, release, pre, post, dev, local) matching __getstate__ before calling __setstate__.
Example fix
// before
import pickle
from pip._vendor.packaging.version import Version
blob = pickle.dumps(Version("1.2.3")) # sent across packaging versions
v = pickle.loads(blob) # may raise "Cannot restore Version from ..."
// after
v = Version(pickle.loads(blob_str)) # serialize the string, re-parse on read Defensive patterns
Strategy: try-catch
Validate before calling
import re
from pip._vendor.packaging.version import Version
def is_restorable_version_state(state):
if isinstance(state, tuple) and len(state) == 6:
return True
if isinstance(state, tuple) and len(state) == 2 and isinstance(state[1], dict):
return all(k in state[1] for k in ('_epoch', '_release'))
if isinstance(state, dict) and state.get('_version') is not None:
return True
return False
def safe_restore(state, fallback_str):
try:
v = Version.__new__(Version)
v.__setstate__(state)
return v
except TypeError:
return Version(fallback_str) Type guard
# No meaningful runtime type guard for opaque pickle state;
# guard by serializing the *string* form instead of the object.
def version_payload(v):
return ('version_str', str(v)) # round-trip str, not the object Try / catch
try:
v = pickle.loads(blob)
except TypeError as e:
if 'Cannot restore Version' in str(e):
raise ValueError('Incompatible packaging pickle; re-create from string') from e
raise Prevention
- Serialize str(version) and re-parse with Version() on read instead of pickling the object.
- Pin the same packaging/pip version on producers and consumers that round-trip Version objects.
- Avoid storing Version objects in long-lived caches that outlive a packaging upgrade.
When it happens
Trigger: Unpickling a Version instance whose pickle payload was produced by an incompatible/modified packaging version, a hand-built state object, or data corrupted in transit/storage. copy.deepcopy, multiprocessing, or caching layers (pickle, shelve, redis) that round-trip Version objects across processes running different packaging versions trigger __setstate__.
Common situations: Upgrading or downgrading pip/packaging in a venv while a cached pickle of a Version object (e.g. from pip's resolver cache, a test fixture, or a user app that pickles parsed versions) survives. Also when a custom __reduce__ or external serializer mangles the Version state.
Related errors
- pylock version {pylock.lock_version} is not supported
- Requested {ireq} has inconsistent Version between its PEP 65
- {}'s Wheel-Version ({}) is not compatible with this version
- Cannot restore {self.__class__.__name__} value from {value!r
- Cannot restore {self.__class__.__name__} from {state!r}
AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04).
Data as JSON: /data/errors/f6d22606cb705a4e.json.
Report an issue: GitHub.