pandas-dev/pandas · error · AttributeError

You cannot add any new attribute '{key}'

Error message

You cannot add any new attribute '{key}'

What it means

Raised by FrozenObject.__setattr__ (via _freeze()) when you try to set a brand-new attribute on a pandas object that has been frozen. Frozen objects (some Index subclasses, etc.) only allow setting attributes already declared on the class or _cache. This guards internal immutability invariants.

Source

Thrown at pandas/core/base.py:161

    def _freeze(self) -> None:
        """
        Prevents setting additional attributes.
        """
        object.__setattr__(self, "__frozen", True)

    # prevent adding any attribute via s.xxx.new_attribute = ...
    def __setattr__(self, key: str, value) -> None:
        # _cache is used by a decorator
        # We need to check both 1.) cls.__dict__ and 2.) getattr(self, key)
        # because
        # 1.) getattr is false for attributes that raise errors
        # 2.) cls.__dict__ doesn't traverse into base classes
        if getattr(self, "__frozen", False) and not (
            key == "_cache"
            or key in type(self).__dict__
            or getattr(self, key, None) is not None
        ):
            raise AttributeError(f"You cannot add any new attribute '{key}'")
        object.__setattr__(self, key, value)


class SelectionMixin(Generic[NDFrameT]):
    """
    mixin implementing the selection & aggregation interface on a group-like
    object sub-classes need to define: obj, exclusions
    """

    obj: NDFrameT
    _selection: IndexLabel | None = None
    exclusions: frozenset[Hashable]
    _internal_names = ["_cache", "__setstate__"]
    _internal_names_set = set(_internal_names)

    @final
    @property
    def _selection_list(self):

View on GitHub (pinned to 71959b8cb9)

Solutions

  1. Store auxiliary data in a separate dict/Series keyed by the object, not as an attribute.
  2. Subclass and declare the attribute at class level if you need it.
  3. Use the .attrs dict (df.attrs['key'] = value) for user metadata.

Example fix

// before
idx.custom = 'meta'  # raises

// after
obj.attrs['custom'] = 'meta'
Defensive patterns

Strategy: try-catch

Validate before calling

allowed = set(type(obj).__dict__) | {'_cache'}
if key not in allowed and getattr(obj, key, None) is None:
    raise AttributeError(f'cannot add attribute {key} to frozen object')

Type guard

def is_frozen(obj) -> bool:
    return getattr(obj, '_FrozenObject__frozen', False) or getattr(obj, '__frozen', False)

Try / catch

try:
    obj.new_attr = value
except AttributeError as e:
    if 'cannot add any new attribute' in str(e):
        obj.attrs['new_attr'] = value
    else:
        raise

Prevention

When it happens

Trigger: Calling `idx.foo = 1` on a frozen Index, or monkey-patching attributes onto instances returned from internal pandas APIs that have invoked _freeze().

Common situations: Attaching metadata to a pandas object; subclassing without overriding __setattr__; stale tutorials suggesting `df.some_attr = ...`.

Related errors


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/dc42326b4374dbbf. Report an issue: GitHub.