{"record":{"id":"19e72ef59a9611a6","repo":"pypa/pip","slug":"cannot-restore-self-class-name-value-fro","errorCode":null,"errorMessage":"Cannot restore {self.__class__.__name__} value from {value!r}","messagePattern":"Cannot restore (.+?) value from (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/packaging/_parser.py","lineNumber":37,"sourceCode":"    def __init__(self, value: str) -> None:\n        self.value = value\n\n    def __str__(self) -> str:\n        return self.value\n\n    def __repr__(self) -> str:\n        return f\"<{self.__class__.__name__}({self.value!r})>\"\n\n    def serialize(self) -> str:\n        raise NotImplementedError\n\n    def __getstate__(self) -> str:\n        # Return just the value string for compactness and stability.\n        return self.value\n\n    def _restore_value(self, value: object) -> None:\n        if not isinstance(value, str):\n            raise TypeError(\n                f\"Cannot restore {self.__class__.__name__} value from {value!r}\"\n            )\n        self.value = value\n\n    def __setstate__(self, state: object) -> None:\n        if isinstance(state, str):\n            # New format (26.2+): just the value string.\n            self._restore_value(state)\n            return\n        if isinstance(state, tuple) and len(state) == 2:\n            # Old format (packaging <= 26.0, __slots__): (None, {slot: value}).\n            _, slot_dict = state\n            if isinstance(slot_dict, dict) and \"value\" in slot_dict:\n                self._restore_value(slot_dict[\"value\"])\n                return\n        if isinstance(state, dict) and \"value\" in state:\n            # Old format (packaging <= 25.0, no __slots__): plain __dict__.\n            self._restore_value(state[\"value\"])","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/pypa/pip/blob/f399c3718970b1b0e2478dac5296eb62679a9b86/src/pip/_vendor/packaging/_parser.py#L19-L55","documentation":"Node is the base class for AST nodes in packaging's dependency-specifier parser (Variable, Value, Op). The _restore_value method is called during unpickling (__setstate__). If the value being restored is not a str, it raises TypeError. This guards against reconstructing parser nodes from invalid data. __setstate__ supports three pickle formats: new compact string (26.2+), old __slots__ tuple (<=26.0), and old __dict__ (<=25.0).","triggerScenarios":"Unpickling a Variable, Value, or Op node where the stored value is not a string: a corrupted pickle, a hand-crafted pickle, or an incompatible serialization from a fork or modified version of packaging.","commonSituations":"Loading cached requirement/marker parse results from disk across packaging version upgrades where the pickle format changed. Deserializing pickled marker data from an untrusted or third-party source.","solutions":["Store serialized strings (via node.serialize()) and re-parse on load instead of pickling Node objects directly","Clear pickle caches when upgrading packaging versions","Catch TypeError on unpickle and fall back to re-parsing from the original requirement string"],"exampleFix":"# before\nimport pickle\nnode = pickle.loads(cached_data)  # may raise TypeError\n\n# after\n# Store the original requirement/marker string, not pickled Node objects\nfrom packaging.requirements import Requirement\ncached_str = \"django>=4.0; python_version >= '3.8'\"\n# On load, always re-parse from string (version-independent):\nreq = Requirement(cached_str)","handlingStrategy":"try-catch","validationCode":"def safe_unpickle_node(data, original_source=None):\n    import pickle\n    try:\n        return pickle.loads(data)\n    except TypeError:\n        return None  # signal re-parse needed","typeGuard":"def is_valid_node_value(value) -> bool:\n    return isinstance(value, str)","tryCatchPattern":"try:\n    node = pickle.loads(cached_data)\nexcept TypeError as e:\n    if \"Cannot restore\" in str(e):\n        from packaging._parser import parse_marker\n        node = parse_marker(original_marker_string)","preventionTips":["Do not pickle internal parser nodes; store serialized strings instead","Re-parse requirement strings on load rather than unpickling","Clear caches when upgrading packaging versions"],"tags":["packaging","pickle","deserialization","version-compat","vendored"],"backgroundTag":null,"analyzedSha":"f399c3718970b1b0e2478dac5296eb62679a9b86","analyzedAt":"2026-08-08T23:01:42.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}