Skip to content

Unable to pickle pydantic model #565

@dreadatour

Description

@dreadatour

After pydantic 2.11.0 release.

It looks like the issue is with references now used for optimizations in Rust code after this change in pydantic-core: pydantic/pydantic-core#1616.

How to reproduce

model-write.py:

from cloudpickle import dumps
from pydantic import BaseModel

class MyModel(BaseModel):
    name: str = ""

serialized = dumps(MyModel)

with open("model.pkl", "wb") as f:
    f.write(serialized)

model-read.py

from cloudpickle import loads

with open("model.pkl", "rb") as f:
    serialized = f.read()

MyModel = loads(serialized)
model = MyModel(name="bar")

assert model.name == "bar"
$ uv pip install cloudpickle pydantic
Using Python 3.13.2 environment at: /Users/vlad/.virtualenvs/test-pydantic
Resolved 6 packages in 131ms
Installed 6 packages in 5ms
 + annotated-types==0.7.0
 + cloudpickle==3.1.1
 + pydantic==2.11.1
 + pydantic-core==2.33.0
 + typing-extensions==4.13.0
 + typing-inspection==0.4.0
$ python model-write.py
$ python model-read.py
Traceback (most recent call last):
  File "/Users/vlad/playground/model-read.py", line 9, in <module>
    assert model.name == "bar"
           ^^^^^^^^^^
  File "/Users/vlad/.virtualenvs/test-pydantic/lib/python3.13/site-packages/pydantic/main.py", line 984, in __getattr__
    raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
AttributeError: 'MyModel' object has no attribute 'name'
$

More details

MyModel.__pydantic_validator__ before serialization:

SchemaValidator(title="MyModel", validator=Model(
    ModelValidator {
        revalidate: Never,
        validator: ModelFields(
            ModelFieldsValidator {
                fields: [
                    Field {
                        name: "name",
                        lookup_key_collection: LookupKeyCollection {
                            by_name: Simple(
                                LookupPath {
                                    first_item: PathItemString {
                                        key: "name",
                                        py_key: Py(
                                            0x0000000101d1bd50,
                                        ),
                                    },
                                    rest: [],
                                },
                            ),
                            by_alias: None,
                            by_alias_then_name: None,
                        },
                        name_py: Py(
                            0x00000001013da278,
                        ),
                        validator: WithDefault(
                            WithDefaultValidator {
                                default: Default(
                                    Py(
                                        0x00000001013d33d8,
                                    ),
                                ),
                                on_error: Raise,
                                validator: Str(
                                    StrValidator {
                                        strict: false,
                                        coerce_numbers_to_str: false,
                                    },
                                ),
                                validate_default: false,
                                copy_default: false,
                                name: "default[str]",
                                undefined: Py(
                                    0x00000001009f4730,
                                ),
                            },
                        ),
                        frozen: false,
                    },
                ],
                model_name: "MyModel",
                extra_behavior: Ignore,
                extras_validator: None,
                extras_keys_validator: None,
                strict: false,
                from_attributes: false,
                loc_by_alias: true,
                validate_by_alias: None,
                validate_by_name: None,
            },
        ),
        class: Py(
            0x000000011f61bd10,
        ),
        generic_origin: None,
        post_init: None,
        frozen: false,
        custom_init: false,
        root_model: false,
        undefined: Py(
            0x00000001009f4730,
        ),
        name: "MyModel",
    },
), definitions=[], cache_strings=True)

MyModel.__pydantic_validator__ after deserialization:

SchemaValidator(title="MyModel", validator=Prebuilt(
    PrebuiltValidator {
        schema_validator: Py(
            0x00000001520eddc0,
        ),
    },
), definitions=[], cache_strings=True)

Even more details

Naive approaches with using register_pickle_by_value does not works.

  1. pydantic_core only:
import cloudpickle
import pydantic_core

cloudpickle.register_pickle_by_value(pydantic_core)

Gives this error on deserialization:

Traceback (most recent call last):
  File "/Users/vlad/playground/model-read.py", line 6, in <module>
    MyModel = cloudpickle.loads(serialized)
AttributeError: type object 'SchemaSerializer' has no attribute 'to_json'
  1. Both pydantic and pydantic_core:
import cloudpickle
import pydantic
import pydantic_core

cloudpickle.register_pickle_by_value(pydantic)
cloudpickle.register_pickle_by_value(pydantic_core)

Gives this error on serialization:

Traceback (most recent call last):
  File "/Users/vlad/playground/model-write.py", line 15, in <module>
    serialized = cloudpickle.dumps(MyModel)
  File "/Users/vlad/.virtualenvs/test-pydantic/lib/python3.13/site-packages/cloudpickle/cloudpickle.py", line 1537, in dumps
    cp.dump(obj)
    ~~~~~~~^^^^^
  File "/Users/vlad/.virtualenvs/test-pydantic/lib/python3.13/site-packages/cloudpickle/cloudpickle.py", line 1303, in dump
    return super().dump(obj)
           ~~~~~~~~~~~~^^^^^
TypeError: cannot pickle 'classmethod_descriptor' object

(related cloudpickle issue: #486)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions