{"record":{"id":"82f31ed409209d43","repo":"Lightning-AI/pytorch-lightning","slug":"type-self-name-object-has-no-attribute","errorCode":null,"errorMessage":"'{type(self).__name__}' object has no attribute '{key}'","messagePattern":"'(.+?)' object has no attribute '(.+?)'","errorType":"exception","errorClass":"AttributeError","httpStatus":null,"severity":"error","filePath":"src/lightning/fabric/utilities/data.py","lineNumber":494,"sourceCode":"        >>> import torch\n        >>> model = torch.nn.Linear(2, 2)\n        >>> state = AttributeDict(model=model, iter_num=0)\n        >>> state.model\n        Linear(in_features=2, out_features=2, bias=True)\n        >>> state.iter_num += 1\n        >>> state.iter_num\n        1\n        >>> state\n        \"iter_num\": 1\n        \"model\":    Linear(in_features=2, out_features=2, bias=True)\n\n    \"\"\"\n\n    def __getattr__(self, key: str) -> Any:\n        try:\n            return self[key]\n        except KeyError as e:\n            raise AttributeError(f\"'{type(self).__name__}' object has no attribute '{key}'\") from e\n\n    def __setattr__(self, key: str, val: Any) -> None:\n        self[key] = val\n\n    def __delattr__(self, item: str) -> None:\n        if item not in self:\n            raise KeyError(item)\n        del self[item]\n\n    def __repr__(self) -> str:\n        if not len(self):\n            return \"\"\n        max_key_length = max(len(str(k)) for k in self)\n        tmp_name = \"{:\" + str(max_key_length + 3) + \"s} {}\"\n        rows = [tmp_name.format(f'\"{n}\":', self[n]) for n in sorted(self.keys())]\n        return \"\\n\".join(rows)\n","sourceCodeStart":476,"sourceCodeEnd":511,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/fabric/utilities/data.py#L476-L511","documentation":"This class is a dict subclass whose `__getattr__` maps attribute access to key lookup (`self[key]`). When code accesses an attribute that is neither a real attribute nor a key in the dict, the KeyError is converted into a standard AttributeError with the class and key name, matching Python's normal attribute-error semantics.","triggerScenarios":"Accessing a missing attribute on Lightning's dict-like wrapper (e.g. `_AttributeDict`): `cfg.some_missing_key`, where 'some_missing_key' was never inserted into the dict.","commonSituations":"Reading configuration/hyperparameter objects (e.g. `hparams` or saved checkpoints restored into an attribute-dict) where a key was renamed between versions or never saved; typos in config key access.","solutions":["Check membership before access: `if 'key' in obj:` or `obj.get('key', default)`.","Use explicit key access `obj['key']` with KeyError handling, or verify available keys via `list(obj.keys())`.","Regenerate/re-save the dict so expected keys exist; align key names across versions."],"exampleFix":"# before\nvalue = cfg.learning_rate  # AttributeError if key absent\n\n# after\nvalue = cfg.get('learning_rate', default_lr)","handlingStrategy":"type-guard","validationCode":"if 'learning_rate' in cfg:\n    lr = cfg['learning_rate']\nelse:\n    lr = default_lr","typeGuard":"def has_key(cfg, key: str) -> bool:\n    return isinstance(cfg, dict) and key in cfg","tryCatchPattern":"try:\n    lr = cfg.learning_rate\nexcept AttributeError:\n    lr = default_lr","preventionTips":["Treat attribute-dicts like dicts: use .get() or membership checks.","Print sorted(obj.keys()) when debugging config access failures.","Pin config key names with constants shared across versions."],"tags":["pytorch-lightning","attribute-dict","config","keyerror"],"backgroundTag":"missing-dict-key","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}