pypa/pip · error · TypeError

Cannot restore Marker from

Error message

Cannot restore Marker from {state!r}

What it means

Raised by Marker.__setstate__ (markers.py:466-468) for the stable 26.2+ pickle format where state is the marker expression string. If that string cannot be re-parsed by _parse_marker (ParserSyntaxError), unpickling raises TypeError('Cannot restore Marker from ...'). The original parse error is chained via 'from exc'.

Solutions

  1. Do not rely on long-lived Marker pickles; store the marker string and rebuild with Marker(...) on load.
  2. Recreate the pickle with the current packaging version.

Example fix

# before (fragile)
import pickle
m = pickle.loads(blob)  # corrupted string
# after (robust)
from packaging.markers import Marker
m = Marker(stored_marker_string)
Defensive patterns

Strategy: validation

Validate before calling

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

def marker_string_reparses(s: str) -> bool:
    try:
        Marker(s)
    except Exception:
        return False
    return True

Try / catch

import pickle
from packaging.markers import Marker

obj = pickle.loads(blob)
if not isinstance(obj, Marker):
    # recreate from the stored string instead of trusting the pickle
    ...

Prevention

When it happens

Trigger: Unpickling a Marker whose stored expression string is malformed — e.g. a hand-crafted pickle, a string corrupted in transit/storage, or a marker string valid under an older packaging grammar that the current parser rejects.

Common situations: Loading pickled requirement/dependency objects across packaging versions; a serialization layer that rewrote or truncated the marker string before pickling.

Related errors


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

Appendix: source

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

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