{"record":{"id":"45d1523372e7f799","repo":"Lightning-AI/pytorch-lightning","slug":"expected-a-list-as-images-found-type-images","errorCode":null,"errorMessage":"Expected a list as \"images\", found {type(images)}","messagePattern":"Expected a list as \"images\", found (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/lightning/pytorch/loggers/wandb.py","lineNumber":492,"sourceCode":"        step: Optional[int] = None,\n    ) -> None:\n        \"\"\"Log text as a Table.\n\n        Can be defined either with `columns` and `data` or with `dataframe`.\n\n        \"\"\"\n\n        self.log_table(key, columns, data, dataframe, step)\n\n    @rank_zero_only\n    def log_image(self, key: str, images: list[Any], step: Optional[int] = None, **kwargs: Any) -> None:\n        \"\"\"Log images (tensors, numpy arrays, PIL Images or file paths).\n\n        Optional kwargs are lists passed to each image (ex: caption, masks, boxes).\n\n        \"\"\"\n        if not isinstance(images, list):\n            raise TypeError(f'Expected a list as \"images\", found {type(images)}')\n        n = len(images)\n        for k, v in kwargs.items():\n            if len(v) != n:\n                raise ValueError(f\"Expected {n} items but only found {len(v)} for {k}\")\n        kwarg_list = [{k: kwargs[k][i] for k in kwargs} for i in range(n)]\n\n        import wandb\n\n        metrics = {key: [wandb.Image(img, **kwarg) for img, kwarg in zip(images, kwarg_list)]}\n        self.log_metrics(metrics, step)  # type: ignore[arg-type]\n\n    @rank_zero_only\n    def log_audio(self, key: str, audios: list[Any], step: Optional[int] = None, **kwargs: Any) -> None:\n        r\"\"\"Log audios (numpy arrays, or file paths).\n\n        Args:\n            key: The key to be used for logging the audio files\n            audios: The list of audio file paths, or numpy arrays to be logged","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/Lightning-AI/pytorch-lightning/blob/9fed5c27d2a62ff0efd6c3573599921d6ff67c14/src/lightning/pytorch/loggers/wandb.py#L474-L510","documentation":"WandbLogger.log_image requires the images argument to be a Python list (each element is then wrapped into wandb.Image with per-item kwargs). Passing a tensor, numpy array, tuple, or generator triggers this TypeError before anything is logged.","triggerScenarios":"logger.log_image(tensor_batch, ...) or logger.log_image(np.array([...]), ...) instead of logger.log_image([t1, t2], ...); also passing a tuple.","commonSituations":"Passing a raw (C,H,W)/(B,C,H,W) torch tensor directly from a training step instead of converting to a list of per-sample tensors/images.","solutions":["Wrap the batch into a list: list(tensor) or images.tolist()/images.cpu() split per sample","Convert numpy arrays: [np_img for np_img in arr]","Unpack tuples/generators: list(images)"],"exampleFix":"# before\nlogger.log_image(images=batch_tensor, caption=[\"a\", \"b\"])\n# after\nlogger.log_image(images=list(batch_tensor), caption=[\"a\", \"b\"])","handlingStrategy":"type-guard","validationCode":"assert isinstance(images, list), \"images must be a list\"","typeGuard":"def is_image_list(x) -> bool:\n    return isinstance(x, list) and len(x) > 0 and all(isinstance(i, (str,)) or hasattr(i, \"__array__\") or torch.is_tensor(i) for i in x)","tryCatchPattern":null,"preventionTips":["Always convert batches to per-sample lists before wandb media calls","Write a small wrapper that normalizes inputs to log_image/log_audio/log_video"],"tags":["wandb","lightning","logging","images","type-error"],"backgroundTag":"invalid-input-type","analyzedSha":"9fed5c27d2a62ff0efd6c3573599921d6ff67c14","analyzedAt":"2026-08-28T11:52:41.083Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}