{"record":{"id":"b7c76bf3176b5f34","repo":"pypa/pip","slug":"cannot-restore-specifierset-from-state-r","errorCode":null,"errorMessage":"Cannot restore SpecifierSet from {state!r}","messagePattern":"Cannot restore SpecifierSet from (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/specifiers.py","lineNumber":931,"sourceCode":"        if isinstance(state, dict):\n            # Old format (packaging <= 25.x, no __slots__): state is a plain dict.\n            specs = state.get(\"_specs\", ())\n            prereleases = state.get(\"_prereleases\")\n            # Convert frozenset to tuple (26.0 stored as frozenset)\n            if isinstance(specs, frozenset):\n                specs = tuple(sorted(specs, key=str))\n            if (\n                isinstance(specs, tuple)\n                and all(isinstance(s, Specifier) for s in specs)\n                and _validate_pre(prereleases)\n            ):\n                self._specs = specs\n                self._prereleases = prereleases\n                self._canonicalized = len(self._specs) <= 1\n                self._has_arbitrary = any(\"===\" in str(s) for s in self._specs)\n                return\n\n        raise TypeError(f\"Cannot restore SpecifierSet from {state!r}\")\n\n    def __repr__(self) -> str:\n        \"\"\"A representation of the specifier set that shows all internal state.\n\n        Note that the ordering of the individual specifiers within the set may not\n        match the input string.\n\n        >>> SpecifierSet('>=1.0.0,!=2.0.0')\n        <SpecifierSet('!=2.0.0,>=1.0.0')>\n        >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=False)\n        <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=False)>\n        >>> SpecifierSet('>=1.0.0,!=2.0.0', prereleases=True)\n        <SpecifierSet('!=2.0.0,>=1.0.0', prereleases=True)>\n        \"\"\"\n        pre = (\n            f\", prereleases={self.prereleases!r}\"\n            if self._prereleases is not None\n            else \"\"","sourceCodeStart":913,"sourceCodeEnd":949,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/specifiers.py#L913-L949","documentation":"Raised as TypeError by SpecifierSet.__setstate__ (specifiers.py:931) during unpickling when none of the recognized state formats validate. It tries the 26.2+ tuple ((Specifier, ...), prereleases), the 26.0-26.1 slot dict (converting a legacy frozenset of specs to a tuple), and the <=25.x plain dict; failure of all raises this. Like the Specifier case, it signals a packaging-version mismatch in pickle state or corrupt hand-built state.","triggerScenarios":"Unpickling a SpecifierSet produced by packaging 26.0 (which stored _specs as a frozenset) in a version that no longer accepts that shape after the frozenset-conversion branch was removed; cross-process pickle transfer between mismatched packaging versions; a spec stored in a frozenset but elements not all Specifier instances.","commonSituations":"Long-lived persistent requirement cache upgraded across a packaging 25->26 or 26.0->26.2 boundary; CI matrix where one job pickles on packaging 26.1 and another loads on 26.3; vendored pip packaging differing from an application's packaging dependency.","solutions":["Store SpecifierSet as str(specifier_set) (round-trippable) rather than pickling the object; reconstruct with SpecifierSet(s) on load.","Ensure producer and consumer run the same packaging version across the pickle boundary.","Invalidate and rebuild any cached/pickled SpecifierSet objects after upgrading packaging.","When loading legacy state, catch TypeError and reconstruct from the string form if available."],"exampleFix":"# before - fragile pickle across packaging versions\nimport pickle\nblob = pickle.dumps(SpecifierSet('>=1.0,!=1.0.1'))\nss = pickle.loads(blob)  # TypeError: Cannot restore SpecifierSet\n\n# after - persist the canonical string\nblob = str(SpecifierSet('>=1.0,!=1.0.1')).encode()\nss = SpecifierSet(blob.decode())","handlingStrategy":"fallback","validationCode":"from packaging.specifiers import SpecifierSet\n# Persist and restore the canonical string, not the pickle.\ndef load_set(s: str) -> 'SpecifierSet':\n    return SpecifierSet(s)","typeGuard":"from packaging.specifiers import Specifier, SpecifierSet\ndef is_specifierset_state(state) -> bool:\n    return (isinstance(state, tuple) and len(state) == 2\n            and isinstance(state[0], tuple)\n            and all(isinstance(s, Specifier) for s in state[0])\n            and (state[1] is None or isinstance(state[1], bool)))","tryCatchPattern":"import pickle\ntry:\n    ss = pickle.loads(blob)\nexcept TypeError:\n    ss = SpecifierSet(blob.decode())","preventionTips":["Store SpecifierSet as its string form for persistence.","Keep packaging versions aligned across pickle producers and consumers.","Rebuild caches after upgrading packaging."],"tags":["packaging","specifiers","pickle","serialization","version-mismatch"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}