PaddlePaddle/PaddleOCR · warning · Exception

You cannot use ``pop`` on a {self.__class__.__name__} instan

Error message

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

What it means

pop is blocked on ModelOutput for the same reason as deletion/mutation: removing keys would desynchronize the dataclass fields from the mapping view, so the method unconditionally raises.

Source

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

                self[class_fields[0].name] = first_field
        else:
            for field in class_fields:
                v = getattr(self, field.name)
                if v is not None:
                    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)

View on GitHub (pinned to 2661c7c0ef)

Solutions

  1. Read the attribute and ignore it instead of removing: value = getattr(output, 'key', None)
  2. Build a filtered copy: kept = ModelOutput(**{k: v for k, v in output.items() if k != 'key'})
  3. Convert to dict for pop-style workflows: d = dict(output.items()); v = d.pop('key', None)

Example fix

# before
loss = out.pop('loss', None)
# after
loss = getattr(out, 'loss', None)  # leave the object intact
Defensive patterns

Strategy: type-guard

Validate before calling

def pop_like(mapping, key, default=None):
    try:
        return mapping[key], mapping  # non-destructive read
    except KeyError:
        return default, mapping

Type guard

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

Try / catch

try:
    v = out.pop('loss')
except Exception as e:
    if 'pop' in str(e):
        v = getattr(out, 'loss', None)
    else:
        raise

Prevention

When it happens

Trigger: Calling output.pop('key') or output.pop('key', default) on a ModelOutput instance, commonly in code that extracts-and-removes fields.

Common situations: Pipeline code that pops intermediate results as they are consumed; generic dict cleanup (popping None values); porting training-loop code that treats every output as a dict.

Related errors


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