{"id":"2f2bdb8a458036c1","repo":"pydantic/pydantic","slug":"self-class-name-is-immutable-and-does","errorCode":null,"errorMessage":"\"{self.__class__.__name__}\" is immutable and does not support item assignment","messagePattern":"\"(.+?)\" is immutable and does not support item assignment","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"pydantic/v1/main.py","lineNumber":382,"sourceCode":"            raise validation_error\n        try:\n            object_setattr(__pydantic_self__, '__dict__', values)\n        except TypeError as e:\n            raise TypeError(\n                'Model values must be a dict; you may not have returned a dictionary from a root validator'\n            ) from e\n        object_setattr(__pydantic_self__, '__fields_set__', fields_set)\n        __pydantic_self__._init_private_attributes()\n\n    @no_type_check\n    def __setattr__(self, name, value):  # noqa: C901 (ignore complexity)\n        if name in self.__private_attributes__ or name in DUNDER_ATTRIBUTES:\n            return object_setattr(self, name, value)\n\n        if self.__config__.extra is not Extra.allow and name not in self.__fields__:\n            raise ValueError(f'\"{self.__class__.__name__}\" object has no field \"{name}\"')\n        elif not self.__config__.allow_mutation or self.__config__.frozen:\n            raise TypeError(f'\"{self.__class__.__name__}\" is immutable and does not support item assignment')\n        elif name in self.__fields__ and self.__fields__[name].final:\n            raise TypeError(\n                f'\"{self.__class__.__name__}\" object \"{name}\" field is final and does not support reassignment'\n            )\n        elif self.__config__.validate_assignment:\n            new_values = {**self.__dict__, name: value}\n\n            for validator in self.__pre_root_validators__:\n                try:\n                    new_values = validator(self.__class__, new_values)\n                except (ValueError, TypeError, AssertionError) as exc:\n                    raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], self.__class__)\n\n            known_field = self.__fields__.get(name, None)\n            if known_field:\n                # We want to\n                # - make sure validators are called without the current value for this field inside `values`\n                # - keep other values (e.g. submodels) untouched (using `BaseModel.dict()` will change them into dicts)","sourceCodeStart":364,"sourceCodeEnd":400,"githubUrl":"https://github.com/pydantic/pydantic/blob/2e5f0e2b4218de31709f1cf9c5bc61ea97a68835/pydantic/v1/main.py#L364-L400","documentation":"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__.)","triggerScenarios":"Setting an attribute on a model declared with frozen=True or allow_mutation=False, including attempts that look like updates inside business logic.","commonSituations":"Using frozen models for caching/hashability, sharing model instances across threads, and forgetting a model is frozen when porting mutable code.","solutions":["If mutation is intended, set Config.frozen=False and allow_mutation=True (or remove frozen=True).","Use model.copy(update={...}) to produce a new instance with changes.","For frozen-by-design data, treat instances as values and replace, not mutate."],"exampleFix":"// before\nclass M(BaseModel):\n    name: str\n    class Config:\n        frozen = True\nm = M(name='x')\nm.name = 'y'  # raises 'is immutable'\n\n// after\nm = m.copy(update={'name': 'y'})\n# or remove frozen if mutation is desired","handlingStrategy":"type-guard","validationCode":"def is_mutable(model_cls) -> bool:\n    cfg = model_cls.__config__\n    return getattr(cfg, 'allow_mutation', True) and not getattr(cfg, 'frozen', False)\n\n# usage\nif not is_mutable(MyModel):\n    raise TypeError(f'{MyModel.__name__} is frozen; use .copy(update=...)')\nm.field = value","typeGuard":"def can_assign(instance) -> bool:\n    cls = type(instance)\n    cfg = cls.__config__\n    return bool(getattr(cfg, 'allow_mutation', True)) and not bool(getattr(cfg, 'frozen', False))","tryCatchPattern":"try:\n    m.field = value\nexcept TypeError as e:\n    if 'immutable' in str(e):\n        m = m.copy(update={'field': value})\n    else:\n        raise","preventionTips":["For frozen models, use model.copy(update={...}) instead of mutation.","Document which models are frozen in module docstrings.","Add tests that assert immutability for value-type models."],"tags":["pydantic","frozen","immutability","setattr","config"],"analyzedSha":"2e5f0e2b4218de31709f1cf9c5bc61ea97a68835","analyzedAt":"2026-08-04T19:54:21.281Z","schemaVersion":2}