pydantic/pydantic · error · TypeError

"{self.__class__.__name__}" is immutable and does not suppor

Error message

"{self.__class__.__name__}" is immutable and does not support item assignment

What it means

Raised by BaseModel.__setattr__ (main.py:382) when assigning to any attribute on a model whose Config has allow_mutation=False or frozen=True. Such models are immutable after construction; any setattr on a non-private, non-dunder attribute is rejected with this TypeError. (Private attributes and DUNDER_ATTRIBUTES bypass this via the earlier branch in __setattr__.)

Source

Thrown at pydantic/v1/main.py:382

            raise validation_error
        try:
            object_setattr(__pydantic_self__, '__dict__', values)
        except TypeError as e:
            raise TypeError(
                'Model values must be a dict; you may not have returned a dictionary from a root validator'
            ) from e
        object_setattr(__pydantic_self__, '__fields_set__', fields_set)
        __pydantic_self__._init_private_attributes()

    @no_type_check
    def __setattr__(self, name, value):  # noqa: C901 (ignore complexity)
        if name in self.__private_attributes__ or name in DUNDER_ATTRIBUTES:
            return object_setattr(self, name, value)

        if self.__config__.extra is not Extra.allow and name not in self.__fields__:
            raise ValueError(f'"{self.__class__.__name__}" object has no field "{name}"')
        elif not self.__config__.allow_mutation or self.__config__.frozen:
            raise TypeError(f'"{self.__class__.__name__}" is immutable and does not support item assignment')
        elif name in self.__fields__ and self.__fields__[name].final:
            raise TypeError(
                f'"{self.__class__.__name__}" object "{name}" field is final and does not support reassignment'
            )
        elif self.__config__.validate_assignment:
            new_values = {**self.__dict__, name: value}

            for validator in self.__pre_root_validators__:
                try:
                    new_values = validator(self.__class__, new_values)
                except (ValueError, TypeError, AssertionError) as exc:
                    raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], self.__class__)

            known_field = self.__fields__.get(name, None)
            if known_field:
                # We want to
                # - make sure validators are called without the current value for this field inside `values`
                # - keep other values (e.g. submodels) untouched (using `BaseModel.dict()` will change them into dicts)

View on GitHub (pinned to 2e5f0e2b42)

Solutions

  1. If mutation is intended, set Config.frozen=False and allow_mutation=True (or remove frozen=True).
  2. Use model.copy(update={...}) to produce a new instance with changes.
  3. For frozen-by-design data, treat instances as values and replace, not mutate.

Example fix

// before
class M(BaseModel):
    name: str
    class Config:
        frozen = True
m = M(name='x')
m.name = 'y'  # raises 'is immutable'

// after
m = m.copy(update={'name': 'y'})
# or remove frozen if mutation is desired
Defensive patterns

Strategy: type-guard

Validate before calling

def is_mutable(model_cls) -> bool:
    cfg = model_cls.__config__
    return getattr(cfg, 'allow_mutation', True) and not getattr(cfg, 'frozen', False)

# usage
if not is_mutable(MyModel):
    raise TypeError(f'{MyModel.__name__} is frozen; use .copy(update=...)')
m.field = value

Type guard

def can_assign(instance) -> bool:
    cls = type(instance)
    cfg = cls.__config__
    return bool(getattr(cfg, 'allow_mutation', True)) and not bool(getattr(cfg, 'frozen', False))

Try / catch

try:
    m.field = value
except TypeError as e:
    if 'immutable' in str(e):
        m = m.copy(update={'field': value})
    else:
        raise

Prevention

When it happens

Trigger: Setting an attribute on a model declared with frozen=True or allow_mutation=False, including attempts that look like updates inside business logic.

Common situations: Using frozen models for caching/hashability, sharing model instances across threads, and forgetting a model is frozen when porting mutable code.

Related errors


AI-assisted analysis of pydantic/pydantic@2e5f0e2b42 (2026-08-04). Data as JSON: /data/errors/2f2bdb8a458036c1.json. Report an issue: GitHub.