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_tensorView on GitHub (pinned to 0132848349)
Solutions
- Permute HWC to CHW: tensor.permute(2, 0, 1) before passing
- Squeeze batch dim: tensor.squeeze(0) if it is (1, C, H, W)
- 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
- Standardize on CHW float tensors at your preprocessing boundary
- Use PIL Images as the interchange format between pipeline stages
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
- Expected CHW image tensor with 1 or 3 channels, got shape {s
- Unsupported image type: {type}
- Unsupported image type: {type(image)}
- Z-Image text embeddings must have shape [seq, dim] or [batch
- Z-Image caption tensor must have rank 2 or 3
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/a7e028ffff43252b.
Report an issue: GitHub.