Skip to content

Python 3.14: RuntimeError: dictionary changed size during iteration during JsonModel class creation (schema_for_fields iterates cls.__dict__) #763

@davidbuck-ortex

Description

@davidbuck-ortex

Summary

On Python 3.14, redis-om-python can crash at import/startup time when constructing a JsonModel, raising:

RuntimeError: dictionary changed size during iteration

This occurs during schema generation (__init_subclass__ → redisearch_schema → schema_for_fields) while iterating directly over the live class namespace (cls.__dict__). The code inside the loop mutates FieldInfo objects, but does not change the class dict size; the size change appears to be coming from concurrent class construction/mutation (likely Pydantic model construction still injecting attributes into the class namespace while redis-om iterates it).

I appreciate that you aren't claiming Python 3.14 compatability at the present time, so this was discovered during my attempts to review my app's third-party dependencies for Python 3.14 compatability.

Environment

  • Python: 3.14
  • redis-om-python: 0.3.5
  • Pydantic: 2.12.5
  • Django: 5.2.10 app importing a JsonModel at startup (error happens at import time)
  • This fails both on AWS Elastic Beanstalk and also locally on MacOS

Stack trace (trimmed)

File ".../redis_cloud/models.py", line 9, in <module>
  class ShortInterest(JsonModel):

File ".../redis_om/model/model.py", line 1916, in __init_subclass__
  cls.redisearch_schema()

File ".../redis_om/model/model.py", line 1985, in redisearch_schema
  schema_parts = [schema_prefix] + cls.schema_for_fields()

File ".../redis_om/model/model.py", line 1995, in schema_for_fields
  for name, field in cls.__dict__.items():
RuntimeError: dictionary changed size during iteration

Code path / failing loop

The failure happens iterating the live cls.__dict__ during model construction:

for name, field in cls.__dict__.items():
    if isinstance(field, FieldInfo):
        if not field.annotation:
            field.annotation = cls.__annotations__.get(name)
        fields[name] = field

The field.annotation = ... assignment mutates the FieldInfo object, but should not add/remove keys on cls.__dict__, so it should not cause a “changed size during iteration” error. The class namespace appears to be modified externally during this phase (likely Pydantic injecting attributes during construction).

I note that in the current version in the repo, this code has moved to aredis_om/model/model.py, but that failing for loop is identical.

Reproduction outline

  1. Define a JsonModel in a Django app
  2. Import the module at startup
  3. __init_subclass__ triggers schema generation
  4. Python 3.14 raises RuntimeError: dictionary changed size during iteration when iterating cls.__dict__

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