Comfy-Org/ComfyUI · error · ValueError

Expected torch.Tensor, got {type(img_tensor)}

Error message

Expected torch.Tensor, got {type(img_tensor)}

What it means

The dataset-save helper accepts either PIL Images or torch tensors per item; when an item is neither, the else branch raises naming the actual type. The preceding code already handles tensors including CHW->HWC permute, so this error specifically means the iterable passed as images contains a foreign object (str path, numpy array, list, None).

Source

Thrown at comfy_extras/nodes_dataset.py:432

                img_tensor = img_tensor.squeeze(0)

            # If tensor is [C, H, W], permute to [H, W, C]
            if img_tensor.dim() == 3 and img_tensor.shape[0] in [1, 3, 4]:
                if (
                    img_tensor.shape[0] <= 4
                    and img_tensor.shape[1] > 4
                    and img_tensor.shape[2] > 4
                ):
                    img_tensor = img_tensor.permute(1, 2, 0)

            # Convert to numpy and scale to 0-255
            img_array = img_tensor.cpu().numpy()
            img_array = np.clip(img_array * 255.0, 0, 255).astype(np.uint8)

            # Convert to PIL Image
            img = Image.fromarray(img_array)
        else:
            raise ValueError(f"Expected torch.Tensor, got {type(img_tensor)}")

        # Save image
        if overwrite:
            filename = f"{prefix}_{idx:05d}.png"
        else:
            _, _, counter, _, resolved_prefix = folder_paths.get_save_image_path(prefix, output_dir)
            filename = f"{resolved_prefix}_{counter:05}_{idx:05d}.png"
        filepath = os.path.join(output_dir, filename)
        img.save(filepath)
        saved_files.append(filename)

    return saved_files


class SaveImageDataSetToFolderNode(io.ComfyNode):
    @classmethod
    def define_schema(cls):
        return io.Schema(

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Convert every item to a torch tensor before saving: torch.from_numpy(arr) for numpy, PILToTensor for images.
  2. Filter out None/str entries before passing the list.
  3. Check the upstream node's declared output type and insert the appropriate conversion node.

Example fix

# before
images = [np.array(pil_img)]
# after
images = [torch.from_numpy(np.array(pil_img)).permute(2, 0, 1)]
Defensive patterns

Strategy: type-guard

Validate before calling

import torch, numpy as np
def coerce_item(x):
    if isinstance(x, torch.Tensor):
        return x
    if isinstance(x, np.ndarray):
        return torch.from_numpy(x)
    if hasattr(x, "convert"):  # PIL
        return PILToTensor()(x)
    raise TypeError(f"cannot coerce {type(x)!r}")

Type guard

def is_savable(x) -> bool:
    return hasattr(x, "save") or isinstance(x, torch.Tensor)

Try / catch

try:
    save_dataset(images)
except ValueError as e:
    if "Expected torch.Tensor" in str(e):
        images = [coerce_item(x) for x in images]
        save_dataset(images)
    else:
        raise

Prevention

When it happens

Trigger: Passing a list containing numpy arrays, file-path strings, or None instead of torch.Tensor / PIL.Image entries — e.g. feeding raw generator output lists or JSON-derived structures straight into the save-dataset node.

Common situations: Version drift where an upstream node changed output from tensors to numpy or to a dict payload; user scripts assembling the list manually and forgetting conversions; None placeholders for skipped items.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/5c5765413c4f39a7. Report an issue: GitHub.