_pickle.PicklingError Could not serialize object TypeError can't pickle _thread.RLock objects
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
This error appears when Python tries to serialize an object graph that contains a thread lock. pickle can only store objects that have a meaningful portable state, and _thread.RLock does not. The fix is usually to separate runtime-only synchronization objects from the data you want to persist or send to another process.
Why RLock Cannot Be Pickled
An RLock is a re-entrant lock used for thread synchronization. Its internal state is tied to the running interpreter, the owning thread, and the current lock count. That state has no useful cross-process representation, so pickle refuses to serialize it.
You can reproduce the failure with a small class:
The important detail is not the exact exception type. The important detail is that the lock is part of the object graph being serialized.
Remove Runtime-Only Fields from Serialized State
If the lock only protects in-memory access and does not represent business data, exclude it from the pickled state and recreate it after deserialization.
This pattern is common when the serialized object contains caches, database connections, thread pools, loggers, or other process-local resources.
Prefer Serializable Data Structures at Process Boundaries
If you are passing work to multiprocessing, job queues, or distributed frameworks, design the message as plain data rather than a live object with synchronization primitives attached.
A plain dictionary, list, tuple, dataclass with serializable fields, or similar structure is much easier to transport safely than a service object.
Dataclasses Need the Same Separation
This problem also appears in dataclasses. The fix is the same: keep the lock out of the serialized state.
The lock exists for safe mutation during runtime, but it should not be treated as durable state.
Do Not Reach for a Different Pickler First
Libraries such as dill or cloudpickle can serialize more Python objects than the standard library, but they do not magically make thread synchronization state portable or semantically meaningful. Even if a tool appears to serialize a larger object graph, you still need to ask whether recreating that runtime state on the other side is correct.
In many codebases, switching serializers only hides the design issue for a while. A clean boundary between serializable data and live runtime resources is usually the stronger fix.
Common Pitfalls
The most common mistake is trying to pickle a service object instead of the data produced by that service. Service objects often contain locks, connections, executors, or clients that cannot be serialized safely.
Another problem is adding a lock to an otherwise serializable class later and forgetting that background workers or caches still pickle instances of that class.
It is also easy to misuse __getstate__ by removing the lock during pickling but forgetting to recreate it in __setstate__. That leaves the restored object in an invalid runtime state.
Finally, using a more powerful serializer does not automatically make concurrent state correct after deserialization.
Summary
- '
_thread.RLockobjects are runtime synchronization primitives, not portable serialized state.' - '
picklefails because a lock cannot be meaningfully reconstructed from bytes alone.' - Exclude locks with
__getstate__and recreate them with__setstate__. - Send plain data across process or network boundaries whenever possible.
- Treat serialization errors as a design signal, not just a library limitation.

