PaddlePaddle/PaddleOCR · warning · Exception

You cannot use ``update`` on a {self.__class__.__name__} ins

Error message

You cannot use ``update`` on a {self.__class__.__name__} instance.

What it means

update is blocked because a bulk dict update could inject undeclared keys into the typed output object. ModelOutput raises on any .update() call to keep field/dict consistency.

Source

Thrown at ppocr/modeling/heads/rec_unimernet_head.py:121

                    self[field.name] = v

    def __delitem__(self, *args, **kwargs):
        raise Exception(
            f"You cannot use ``__delitem__`` on a {self.__class__.__name__} instance."
        )

    def setdefault(self, *args, **kwargs):
        raise Exception(
            f"You cannot use ``setdefault`` on a {self.__class__.__name__} instance."
        )

    def pop(self, *args, **kwargs):
        raise Exception(
            f"You cannot use ``pop`` on a {self.__class__.__name__} instance."
        )

    def update(self, *args, **kwargs):
        raise Exception(
            f"You cannot use ``update`` on a {self.__class__.__name__} instance."
        )

    def __getitem__(self, k):
        if isinstance(k, str):
            inner_dict = dict(self.items())
            return inner_dict[k]
        else:
            return self.to_tuple()[k]

    def __setattr__(self, name, value):
        if name in self.keys() and value is not None:
            super().__setitem__(name, value)
        super().__setattr__(name, value)

    def __setitem__(self, key, value):
        super().__setitem__(key, value)
        super().__setattr__(key, value)

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Merge at the dict level: merged = {**output.to_dict(), **extra} and construct a new ModelOutput if needed
  2. Set individual attributes instead: output.some_metric = value (typed assignment keeps the invariant)
  3. Return a plain dict from your wrapper if callers need mutable dict semantics

Example fix

# before
out.update({'cer': 0.02})
# after
merged = {**dict(out.items()), 'cer': 0.02}
Defensive patterns

Strategy: type-guard

Validate before calling

def merge_output(output, extra: dict) -> dict:
    return {**dict(output.items()), **extra}
# merged = merge_output(out, {'cer': 0.02}) instead of out.update(...)

Type guard

def is_model_output(obj) -> bool:
    return hasattr(obj, '__dataclass_fields__') and hasattr(obj, 'to_tuple')

Try / catch

try:
    out.update(extra)
except Exception as e:
    if 'update' in str(e):
        out = {**dict(out.items()), **extra}
    else:
        raise

Prevention

When it happens

Trigger: Calling output.update(other_dict) or output.update(**kwargs) on a ModelOutput, e.g. merging extra metrics into the head's output.

Common situations: Accumulating loss/metric dicts across modules and update()-ing them into the model output; generic logging code that enriches any dict-like return value; merging outputs of two heads.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/f6b1ce1fc9a638d0. Report an issue: GitHub.