{"record":{"id":"77a1c9d427b7546c","repo":"python/cpython","slug":"cannot-pickle-self-class-name-r-object","errorCode":null,"errorMessage":"cannot pickle {self.__class__.__name__!r} object","messagePattern":"cannot pickle (.+?) object","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/_pyio.py","lineNumber":851,"sourceCode":"\n    @property\n    def raw(self):\n        return self._raw\n\n    @property\n    def closed(self):\n        return self.raw.closed\n\n    @property\n    def name(self):\n        return self.raw.name\n\n    @property\n    def mode(self):\n        return self.raw.mode\n\n    def __getstate__(self):\n        raise TypeError(f\"cannot pickle {self.__class__.__name__!r} object\")\n\n    def __repr__(self):\n        modname = self.__class__.__module__\n        clsname = self.__class__.__qualname__\n        try:\n            name = self.name\n        except AttributeError:\n            return \"<{}.{}>\".format(modname, clsname)\n        else:\n            return \"<{}.{} name={!r}>\".format(modname, clsname, name)\n\n    def _dealloc_warn(self, source):\n        if dealloc_warn := getattr(self.raw, \"_dealloc_warn\", None):\n            dealloc_warn(source)\n\n    ### Lower-level APIs ###\n\n    def fileno(self):","sourceCodeStart":833,"sourceCodeEnd":869,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pyio.py#L833-L869","documentation":"IOBase.__getstate__ (Lib/_pyio.py:851) deliberately raises TypeError to make file objects unpicklable: open streams wrap OS descriptors, sockets, or memory state that cannot be serialized meaningfully. Any pickling path (pickle.dumps, copy.deepcopy, multiprocessing transfer, functools.cache-style caching) hits this.","triggerScenarios":"pickle.dumps(open_file); passing an open file or buffered reader as an argument to multiprocessing.Process or a Pool; copy.deepcopy(f); putting file objects in objects sent over a queue.","commonSituations":"Sending a config object to worker processes where one field accidentally holds an open file; deepcopy of request contexts that captured an upload stream; caching functions that pickle their results/inputs.","solutions":["Pickling the contents instead of the handle: read first, then pickle `f.read()` bytes or the parsed data.","In multiprocessing, pass file paths (or file descriptors via multiprocessing.reduction) rather than file objects.","For deep structures, implement __getstate__ on your own class that excludes file fields and reopens in __setstate__.","As a last resort, use a library that supports pickling handles (dill/cloudpickle), understanding the target process must be able to use the descriptor."],"exampleFix":"# before\nf = open('model.bin', 'rb')\npickle.dumps(f)  # TypeError: cannot pickle 'BufferedReader' object\n\n# after\nwith open('model.bin', 'rb') as f:\n    blob = f.read()\npickle.dumps(blob)","handlingStrategy":"type-guard","validationCode":"def pickle_payload(obj):\n    import pickle\n    for attr, val in vars(obj).items():\n        if isinstance(val, io.IOBase):\n            raise TypeError(f'{attr} is an open stream; extract data before pickling')\n    return pickle.dumps(obj)","typeGuard":"def is_unpicklable_stream(v) -> bool:\n    return isinstance(v, (io.IOBase, io.BufferedIOBase, io.TextIOBase))","tryCatchPattern":"try:\n    blob = pickle.dumps(obj)\nexcept TypeError as e:\n    if 'cannot pickle' in str(e):\n        raise TypeError('strip file handles before serializing') from e\n    raise","preventionTips":["Never store open file objects in objects destined for pickle/multiprocessing queues.","Pass paths or bytes, not handles, across process boundaries.","Add a __getstate__ to your own classes that drops file fields and reopens lazily in __setstate__."],"tags":["io","pickle","serialization","typeerror","multiprocessing"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}