sgl-project/sglang · error · TypeError
Expected CHW image tensor, got 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.
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
- Unsupported image type
- audio must be a 2D tensor, but got
- f"Expected camera embedding shape [B, C, F, H, W], got
- f"Input shape must be divisible by patch_size
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/a7e028ffff43252b.
Report an issue: GitHub.
Appendix: 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)