{"record":{"id":"636608c91540e368","repo":"PaddlePaddle/PaddleOCR","slug":"you-cannot-use-delitem-on-a-self-class","errorCode":null,"errorMessage":"You cannot use ``__delitem__`` on a {self.__class__.__name__} instance.","messagePattern":"You cannot use ``__delitem__`` on a (.+?) instance\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"warning","filePath":"ppocr/modeling/heads/rec_unimernet_head.py","lineNumber":106,"sourceCode":"                            self[class_fields[0].name] = first_field\n                        else:\n                            raise ValueError(\n                                f\"Cannot set key/value for {element}. It needs to be a tuple (key, value).\"\n                            )\n                        break\n                    setattr(self, element[0], element[1])\n                    if element[1] is not None:\n                        self[element[0]] = element[1]\n            elif first_field is not None:\n                self[class_fields[0].name] = first_field\n        else:\n            for field in class_fields:\n                v = getattr(self, field.name)\n                if v is not None:\n                    self[field.name] = v\n\n    def __delitem__(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``__delitem__`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def setdefault(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``setdefault`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def pop(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``pop`` on a {self.__class__.__name__} instance.\"\n        )\n\n    def update(self, *args, **kwargs):\n        raise Exception(\n            f\"You cannot use ``update`` on a {self.__class__.__name__} instance.\"\n        )\n","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/PaddlePaddle/PaddleOCR/blob/2661c7c0ef5c613e8f93c6e93b2e052399f0f854/ppocr/modeling/heads/rec_unimernet_head.py#L88-L124","documentation":"The ModelOutput class in the UniMERNet head intentionally blocks dict-style destructive mutation; __delitem__ always raises so that users cannot silently delete declared dataclass fields and desync attribute/dict views.","triggerScenarios":"Calling del output['loss'] (or any __delitem__ use) on a ModelOutput instance returned by the head/loss computation.","commonSituations":"Treating ModelOutput like a plain dict in generic cleanup/aggregation code; copying dict-manipulation utilities over outputs; trying to strip fields before logging/serialization.","solutions":["Do not delete keys; build a new object with only the fields you want (e.g. construct another ModelOutput with the kept kwargs)","If you need a mutable dict, convert first: d = output.to_dict() if available, or dict(output.items()), then delete from d","Select fields via attribute access (output.logits) instead of removing the ones you don't want"],"exampleFix":"# before\ndel output['loss']\n# after\nlossless = {k: v for k, v in output.items() if k != 'loss'}","handlingStrategy":"type-guard","validationCode":"def is_model_output(obj) -> bool:\n    return type(obj).__name__ == 'ModelOutput' or hasattr(obj, 'to_tuple') and hasattr(obj, '__dataclass_fields__')","typeGuard":"def is_model_output(obj) -> bool:\n    return hasattr(obj, '__dataclass_fields__') and hasattr(obj, 'to_tuple')","tryCatchPattern":"null  # intentional guard; branch on type instead of catching","preventionTips":["Route deletion through a plain dict copy: {k: v for k, v in out.items() if k != target}","Teammates: ModelOutput is read-mostly; treat attribute access as the API","Lint for del/['...'] patterns on model outputs in shared utils"],"tags":["model-output","immutable","unimernet","api-misuse"],"backgroundTag":null,"analyzedSha":"2661c7c0ef5c613e8f93c6e93b2e052399f0f854","analyzedAt":"2026-08-14T20:17:30.180Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}