sgl-project/sglang · error · TypeError

Expected CHW image tensor, got shape {shape}

Error message

Expected CHW image tensor, got shape {shape}

What it means

The Step3-VL multimodal preprocessor's image transform only accepts 3-dimensional torch tensors in CHW layout (channels, height, width). Passing a batched tensor (4D), a flat vector (1D), or an HWC tensor raises this TypeError before any normalization happens. The check runs first in forward() so downstream shape math never sees malformed input.

Source

Thrown at python/sglang/srt/multimodal/processors/step3_vl.py:37

    BaseMultimodalProcessor as SGLangBaseProcessor,
)
from sglang.srt.multimodal.processors.base_processor import (
    MultimodalSpecialTokens,
)

Step3Image = Union[Image.Image, torch.Tensor]
ImageWithPatches = tuple[Step3Image, list[Step3Image], list[int] | None]


class GPUToTensor(torch.nn.Module):

    def forward(
        self, raw_image: Union[np.ndarray, Image.Image, torch.Tensor]
    ) -> torch.Tensor:
        if isinstance(raw_image, torch.Tensor):
            image_tensor = raw_image
            if image_tensor.ndim != 3:
                raise TypeError(
                    f"Expected CHW image tensor, got shape {tuple(image_tensor.shape)}"
                )
            if image_tensor.shape[0] == 1:
                image_tensor = image_tensor.repeat(3, 1, 1)
            elif image_tensor.shape[0] != 3:
                raise TypeError(
                    f"Expected CHW image tensor with 1 or 3 channels, got shape {tuple(image_tensor.shape)}"
                )
            if image_tensor.dtype == torch.uint8:
                image_tensor = image_tensor.to(torch.float32).div(255)
            elif not image_tensor.is_floating_point():
                image_tensor = image_tensor.to(torch.float32)
            return image_tensor.contiguous()
        if isinstance(raw_image, Image.Image):
            image_tensor = transforms.ToTensor()(raw_image)
            if torch.cuda.is_available():
                image_tensor = image_tensor.to(torch.device("cuda"))
            return image_tensor

View on GitHub (pinned to 0132848349)

Solutions

  1. Permute HWC to CHW: tensor.permute(2, 0, 1) before passing
  2. Squeeze batch dim: tensor.squeeze(0) if it is (1, C, H, W)
  3. Pass a PIL Image or numpy HWC array instead of a raw tensor — the transform handles those natively

Example fix

# before
img = torch.from_numpy(np_image)  # HWC
t = transform(img)
# after
img = torch.from_numpy(np_image).permute(2, 0, 1)  # -> CHW
t = transform(img)
Defensive patterns

Strategy: validation

Validate before calling

def to_chw(t: torch.Tensor) -> torch.Tensor:
    if t.ndim == 4 and t.shape[0] == 1:
        t = t.squeeze(0)
    if t.ndim == 3 and t.shape[-1] in (1, 3) and t.shape[0] not in (1, 3):
        t = t.permute(2, 0, 1)
    assert t.ndim == 3, f'expected CHW, got {tuple(t.shape)}'
    return t

Type guard

def is_chw_tensor(t) -> bool:
    return isinstance(t, torch.Tensor) and t.ndim == 3

Prevention

When it happens

Trigger: Calling Step3VlImageTransform.forward (or the processor pipeline that uses it) with a torch.Tensor whose ndim != 3, e.g. a (1,3,224,224) batched tensor, a (224,224,3) HWC tensor, or a (224,224) grayscale tensor.

Common situations: Feeding tensors produced by torchvision DataLoader (usually BCHW) or by numpy-based code that converts with torch.from_numpy(img) keeping HWC order; passing an already-preprocessed batch instead of a single image.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/a7e028ffff43252b. Report an issue: GitHub.