{"record":{"id":"91f562d35781c844","repo":"Lightning-AI/pytorch-lightning","slug":"self-log-dict-dictionary-was-called-but-nest","errorCode":null,"errorMessage":"`self.log_dict({dictionary})` was called, but nested dictionaries cannot be logged","messagePattern":"`self\\.log_dict\\((.+?)\\)` was called, but nested dictionaries cannot be logged","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/core/module.py","lineNumber":642,"sourceCode":"                enable_graph=enable_graph,\n                sync_dist=sync_dist,\n                sync_dist_group=sync_dist_group,\n                add_dataloader_idx=add_dataloader_idx,\n                batch_size=batch_size,\n                rank_zero_only=rank_zero_only,\n            )\n        return None\n\n    def _log_dict_through_fabric(\n        self, dictionary: Union[Mapping[str, _METRIC], MetricCollection], logger: Optional[bool] = None\n    ) -> None:\n        if logger is False:\n            # Passing `logger=False` with Fabric does not make much sense because there is no other destination to\n            # log to, but we support it in case the original code was written for Trainer use\n            return\n\n        if any(isinstance(v, dict) for v in dictionary.values()):\n            raise ValueError(f\"`self.log_dict({dictionary})` was called, but nested dictionaries cannot be logged\")\n        for name, value in dictionary.items():\n            apply_to_collection(value, object, self.__check_allowed, name, value, wrong_dtype=(numbers.Number, Tensor))\n\n        assert self._fabric is not None\n        self._fabric.log_dict(metrics=dictionary)  # type: ignore[arg-type]\n\n    @staticmethod\n    def __check_not_nested(value: dict, name: str) -> None:\n        # self-imposed restriction. for simplicity\n        if any(isinstance(v, dict) for v in value.values()):\n            raise ValueError(f\"`self.log({name}, {value})` was called, but nested dictionaries cannot be logged\")\n\n    @staticmethod\n    def __check_allowed(v: Any, name: str, value: Any) -> None:\n        raise ValueError(f\"`self.log({name}, {value})` was called, but `{type(v).__name__}` values cannot be logged\")\n\n    def __to_tensor(self, value: Union[Tensor, numbers.Number], name: str) -> Tensor:\n        value = (","sourceCodeStart":624,"sourceCodeEnd":660,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/core/module.py#L624-L660","documentation":"In Fabric mode (LightningModule used via lightning.fabric), _log_dict_through_fabric validates that the dictionary passed to self.log_dict contains only flat values. Any value that is itself a dict makes serialization ambiguous and raises ValueError.","triggerScenarios":"Calling self.log_dict({'outer': {'inner': 1}}) on a module attached to Fabric (self._fabric is not None).","commonSituations":"User migrated Trainer code to Fabric and logged a nested metrics structure; aggregated metrics into per-dataset dicts before logging.","solutions":["Flatten the dictionary into scalar/tensor leaves: {'outer/inner': 1}","Log each inner key separately with self.log_dict on the flattened mapping"],"exampleFix":"# before\nself.log_dict({'train': {'loss': loss, 'acc': acc}})\n\n# after\nself.log_dict({'train/loss': loss, 'train/acc': acc})","handlingStrategy":"validation","validationCode":"def flatten(d, prefix=''):\n    out = {}\n    for k, v in d.items():\n        key = f'{prefix}/{k}' if prefix else k\n        if isinstance(v, dict):\n            out.update(flatten(v, key))\n        else:\n            out[key] = v\n    return out\nself.log_dict(flatten(metrics))","typeGuard":"def is_flat_metric_dict(d) -> bool:\n    return all(not isinstance(v, dict) for v in d.values())","tryCatchPattern":null,"preventionTips":["Flatten nested metric structures at the source","Standardize on 'a/b' style keys for grouped metrics"],"tags":["pytorch-lightning","fabric","log-dict","nested-dict","validation"],"backgroundTag":"nested-metrics-dict","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}