Comfy-Org/ComfyUI · error · ValueError

Expected 4D image tensor, got {type(item).__name__} shape {g

Error message

Expected 4D image tensor, got {type(item).__name__} shape {getattr(item, 'shape', None)}

What it means

The second branch of _ensure_image_list handles iterables of tensors: each item must itself be a 4D torch.Tensor. This raise covers both failure modes at once — a non-tensor item (type name shown) and a wrong-dimensionality tensor (shape shown via getattr) — producing one message that names the offending item's type and shape.

Source

Thrown at comfy_extras/nodes_dataset.py:660

        if not has_process and not has_group:
            raise ValueError(
                f"{cls.__name__}: Must override either _process or _group_process"
            )

        return has_group

    @classmethod
    def _ensure_image_list(cls, images):
        """Normalize to a flat list of [1, H, W, C] tensors."""
        if isinstance(images, torch.Tensor):
            if images.ndim != 4:
                raise ValueError(f"Expected 4D image tensor, got shape {tuple(images.shape)}")
            return [images[i:i+1] for i in range(images.shape[0])]

        flat = []
        for item in images:
            if not isinstance(item, torch.Tensor) or item.ndim != 4:
                raise ValueError(f"Expected 4D image tensor, got {type(item).__name__} shape {getattr(item, 'shape', None)}")
            flat.extend([item[i:i+1] for i in range(item.shape[0])])
        return flat

    @classmethod
    def define_schema(cls):
        if cls.node_id is None:
            raise NotImplementedError(f"{cls.__name__} must set node_id class variable")

        is_group = cls._detect_processing_mode()

        # Auto-detect is_output_list if not explicitly set
        # Single processing: False (backend collects results into list)
        # Group processing: True by default (can be False for single-output nodes)
        output_is_list = (
            cls.is_output_list if cls.is_output_list is not None else is_group
        )

        inputs = [

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Normalize every list item to a 4D tensor: convert numpy via torch.from_numpy(...).permute(2,0,1).unsqueeze(0).
  2. Ensure per-item slices keep 4D: use images[i:i+1], not images[i].
  3. Drop or convert non-tensor entries before calling the node.

Example fix

# before
imgs = [images[i] for i in range(images.shape[0])]     # each (H, W, C)
# after
imgs = [images[i:i + 1] for i in range(images.shape[0])]  # each (1, H, W, C)
Defensive patterns

Strategy: type-guard

Validate before calling

import torch
def flatten_batches(items):
    flat = []
    for it in items:
        if not isinstance(it, torch.Tensor) or it.ndim != 4:
            raise TypeError(f"bad item {type(it).__name__}")
        flat.extend([it[i:i+1] for i in range(it.shape[0])])
    return flat

Type guard

def all_4d_tensors(items) -> bool:
    return all(isinstance(it, torch.Tensor) and it.ndim == 4 for it in items)

Prevention

When it happens

Trigger: Passing a list like [np.ndarray, ...], [tensor_3d, ...], [None], or mixed tensor/PIL lists to a dataset processing node. Any single bad item aborts the whole flatten.

Common situations: Heterogeneous lists built from multiple sources (some numpy, some tensors); per-item slicing that dropped batch dims on only some entries; empty non-tensor sentinels mixed into results.

Related errors


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