python/cpython · error · TypeError

cannot pickle {self.__class__.__name__!r} object

Error message

cannot pickle {self.__class__.__name__!r} object

What it means

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.

Source

Thrown at Lib/_pyio.py:851

    @property
    def raw(self):
        return self._raw

    @property
    def closed(self):
        return self.raw.closed

    @property
    def name(self):
        return self.raw.name

    @property
    def mode(self):
        return self.raw.mode

    def __getstate__(self):
        raise TypeError(f"cannot pickle {self.__class__.__name__!r} object")

    def __repr__(self):
        modname = self.__class__.__module__
        clsname = self.__class__.__qualname__
        try:
            name = self.name
        except AttributeError:
            return "<{}.{}>".format(modname, clsname)
        else:
            return "<{}.{} name={!r}>".format(modname, clsname, name)

    def _dealloc_warn(self, source):
        if dealloc_warn := getattr(self.raw, "_dealloc_warn", None):
            dealloc_warn(source)

    ### Lower-level APIs ###

    def fileno(self):

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pickling the contents instead of the handle: read first, then pickle `f.read()` bytes or the parsed data.
  2. In multiprocessing, pass file paths (or file descriptors via multiprocessing.reduction) rather than file objects.
  3. For deep structures, implement __getstate__ on your own class that excludes file fields and reopens in __setstate__.
  4. As a last resort, use a library that supports pickling handles (dill/cloudpickle), understanding the target process must be able to use the descriptor.

Example fix

# before
f = open('model.bin', 'rb')
pickle.dumps(f)  # TypeError: cannot pickle 'BufferedReader' object

# after
with open('model.bin', 'rb') as f:
    blob = f.read()
pickle.dumps(blob)
Defensive patterns

Strategy: type-guard

Validate before calling

def pickle_payload(obj):
    import pickle
    for attr, val in vars(obj).items():
        if isinstance(val, io.IOBase):
            raise TypeError(f'{attr} is an open stream; extract data before pickling')
    return pickle.dumps(obj)

Type guard

def is_unpicklable_stream(v) -> bool:
    return isinstance(v, (io.IOBase, io.BufferedIOBase, io.TextIOBase))

Try / catch

try:
    blob = pickle.dumps(obj)
except TypeError as e:
    if 'cannot pickle' in str(e):
        raise TypeError('strip file handles before serializing') from e
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/77a1c9d427b7546c. Report an issue: GitHub.