Lightning-AI/pytorch-lightning · error · ValueError

`self.log({name}, {value})` was called, but `{type(v).__name

Error message

`self.log({name}, {value})` was called, but `{type(v).__name__}` values cannot be logged

What it means

__check_allowed runs apply_to_collection over logged values and raises for any element whose type is neither a numbers.Number nor a Tensor. Strings, lists of strings, arbitrary objects, etc. cannot be logged as metrics.

Source

Thrown at src/lightning/pytorch/core/module.py:657

            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 = (
            value.clone().detach()
            if isinstance(value, Tensor)
            else torch.tensor(value, device=self.device, dtype=_get_default_dtype())
        )
        if not torch.numel(value) == 1:
            raise ValueError(
                f"`self.log({name}, {value})` was called, but the tensor must have a single element."
                f" You can try doing `self.log({name}, {value}.mean())`"
            )
        value = value.squeeze()
        return value

    def all_gather(
        self, data: Union[Tensor, dict, list, tuple], group: Optional[Any] = None, sync_grads: bool = False
    ) -> Union[Tensor, dict, list, tuple]:

View on GitHub (pinned to 9fed5c27d2)

Solutions

  1. Log only numbers/Tensors; convert strings to ids or log text via a dedicated text logger (e.g. TensorBoardLogger.add_text)
  2. For categorical values, map to integer codes before logging
  3. Remove non-numeric entries from the logged dict

Example fix

# before
self.log('pred_label', 'cat')

# after
code = label_to_id('cat')
self.log('pred_label_id', code)
# or: self.logger.experiment.add_text('pred_label', 'cat', step)
Defensive patterns

Strategy: type-guard

Validate before calling

import numbers
from torch import Tensor
def loggable(v) -> bool:
    return isinstance(v, (numbers.Number, Tensor))
metrics = {k: v for k, v in metrics.items() if loggable(v)}

Type guard

def is_loggable_value(v) -> bool:
    import numbers
    from torch import Tensor
    return isinstance(v, (numbers.Number, Tensor))

Prevention

When it happens

Trigger: self.log('label', 'cat') (a str), self.log('names', ['a','b']), or logging a non-numeric object under Fabric.

Common situations: User tries to log text predictions, class names, or configuration strings as if they were metrics; accidentally passes a tuple/list of mixed objects.

Related errors


AI-assisted analysis of Lightning-AI/pytorch-lightning@9fed5c27d2 (2026-08-28). Data as JSON: /api/errors/54717f65290d853c. Report an issue: GitHub.