pypa/pip · error · TypeError

Cannot restore Marker from {state!r}

Error message

Cannot restore Marker from {state!r}

What it means

Raised as TypeError from Marker.__setstate__ when unpickling/copying a Marker whose pickled state is the new (packaging 26.2+) string format, but that string cannot be re-parsed by _parse_marker (raises ParserSyntaxError). The string was supposed to be a valid PEP 508 marker expression but is malformed when restored.

Source

Thrown at src/pip/_vendor/packaging/markers.py:405

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Marker):
            return NotImplemented

        return str(self) == str(other)

    def __getstate__(self) -> str:
        # Return the marker expression string for compactness and stability.
        # Internal Node objects are excluded; the string is re-parsed on load.
        return str(self)

    def __setstate__(self, state: object) -> None:
        if isinstance(state, str):
            # New format (26.2+): just the marker expression string.
            try:
                self._markers = _normalize_extra_values(_parse_marker(state))
            except ParserSyntaxError as exc:
                raise TypeError(f"Cannot restore Marker from {state!r}") from exc
            return
        if isinstance(state, dict) and "_markers" in state:
            # Old format (packaging <= 26.1, no __slots__): plain __dict__.
            markers = state["_markers"]
            if isinstance(markers, list):
                self._markers = markers
                return
        if isinstance(state, tuple) and len(state) == 2:
            # Old format (packaging <= 26.1, __slots__): (None, {slot: value}).
            _, slot_dict = state
            if isinstance(slot_dict, dict) and "_markers" in slot_dict:
                markers = slot_dict["_markers"]
                if isinstance(markers, list):
                    self._markers = markers
                    return
        raise TypeError(f"Cannot restore Marker from {state!r}")

    def __and__(self, other: Marker) -> Marker:

View on GitHub (pinned to d7d0d0a394)

Solutions

  1. Regenerate the Marker from its source string with Marker(expr) instead of unpickling a stale object.
  2. If caching, store the marker expression string and reconstruct Marker(...) on load rather than pickling the object.
  3. Catch TypeError around pickle.loads / copy operations and rebuild the Marker from the original expression.
  4. Validate the cached string with Marker(str) before persisting, so corrupt data is never written.

Example fix

# before
import pickle
m = pickle.loads(cached_bytes)
# after
expr = load_expression_string_from_cache()
m = Marker(expr)
Defensive patterns

Strategy: try-catch

Validate before calling

from packaging.markers import Marker
from packaging.markers import ParserSyntaxError

def validate_marker_string(s: str) -> bool:
    try:
        Marker(s)
        return True
    except ParserSyntaxError:
        return False

Try / catch

import pickle
try:
    m = pickle.loads(data)
except TypeError as e:
    if 'Cannot restore Marker' in str(e):
        m = Marker(stored_expr_str)
    else:
        raise

Prevention

When it happens

Trigger: Unpickling a Marker object whose serialized expression string got corrupted (e.g. truncated in a cache, mutated in a database). Using copy.deepcopy on a Marker whose __getstate__ returned a non-expression string subclass. Loading a pickle produced by a buggy custom __reduce__.

Common situations: Cross-process caches (multiprocessing, redis) storing pickled Marker objects; rolling a cache forward/backward across packaging versions; test fixtures with hand-edited pickle bytes.

Related errors


AI-assisted analysis of pypa/pip@d7d0d0a394 (2026-08-04). Data as JSON: /data/errors/5e9b4171bf9484c3.json. Report an issue: GitHub.