Lightning-AI/pytorch-lightning · error · ValueError
`self.log_dict({dictionary})` was called, but nested diction
Error message
`self.log_dict({dictionary})` was called, but nested dictionaries cannot be logged What it means
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.
Source
Thrown at src/lightning/pytorch/core/module.py:642
enable_graph=enable_graph,
sync_dist=sync_dist,
sync_dist_group=sync_dist_group,
add_dataloader_idx=add_dataloader_idx,
batch_size=batch_size,
rank_zero_only=rank_zero_only,
)
return None
def _log_dict_through_fabric(
self, dictionary: Union[Mapping[str, _METRIC], MetricCollection], logger: Optional[bool] = None
) -> None:
if logger is False:
# Passing `logger=False` with Fabric does not make much sense because there is no other destination to
# log to, but we support it in case the original code was written for Trainer use
return
if any(isinstance(v, dict) for v in dictionary.values()):
raise ValueError(f"`self.log_dict({dictionary})` was called, but nested dictionaries cannot be logged")
for name, value in dictionary.items():
apply_to_collection(value, object, self.__check_allowed, name, value, wrong_dtype=(numbers.Number, Tensor))
assert self._fabric is not None
self._fabric.log_dict(metrics=dictionary) # type: ignore[arg-type]
@staticmethod
def __check_not_nested(value: dict, name: str) -> None:
# self-imposed restriction. for simplicity
if any(isinstance(v, dict) for v in value.values()):
raise ValueError(f"`self.log({name}, {value})` was called, but nested dictionaries cannot be logged")
@staticmethod
def __check_allowed(v: Any, name: str, value: Any) -> None:
raise ValueError(f"`self.log({name}, {value})` was called, but `{type(v).__name__}` values cannot be logged")
def __to_tensor(self, value: Union[Tensor, numbers.Number], name: str) -> Tensor:
value = (View on GitHub (pinned to 9fed5c27d2)
Solutions
- Flatten the dictionary into scalar/tensor leaves: {'outer/inner': 1}
- Log each inner key separately with self.log_dict on the flattened mapping
Example fix
# before
self.log_dict({'train': {'loss': loss, 'acc': acc}})
# after
self.log_dict({'train/loss': loss, 'train/acc': acc}) Defensive patterns
Strategy: validation
Validate before calling
def flatten(d, prefix=''):
out = {}
for k, v in d.items():
key = f'{prefix}/{k}' if prefix else k
if isinstance(v, dict):
out.update(flatten(v, key))
else:
out[key] = v
return out
self.log_dict(flatten(metrics)) Type guard
def is_flat_metric_dict(d) -> bool:
return all(not isinstance(v, dict) for v in d.values()) Prevention
- Flatten nested metric structures at the source
- Standardize on 'a/b' style keys for grouped metrics
When it happens
Trigger: Calling self.log_dict({'outer': {'inner': 1}}) on a module attached to Fabric (self._fabric is not None).
Common situations: User migrated Trainer code to Fabric and logged a nested metrics structure; aggregated metrics into per-dataset dicts before logging.
Related errors
- `self.log({name}, {value})` was called, but nested dictionar
- `setup_optimizers` requires at least one optimizer as input.
- `setup_dataloaders` requires at least one dataloader as inpu
- Device should be CUDA, got {device} instead.
- You requested to find {num_devices} devices but there are no
AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28).
Data as JSON: /api/errors/91f562d35781c844.
Report an issue: GitHub.