sgl-project/sglang · error · ValueError

Packed pixel_values token count does not match spatial_shape

Error message

Packed pixel_values token count does not match spatial_shapes: {pixel_values_flat.shape[0]} vs {total_tokens}.

What it means

Siglip2VisionModel.forward with packed (flattened, variable-resolution) pixel_values checks that the first dimension of pixel_values equals the sum of H*W over spatial_shapes. A mismatch means the image tensor and the per-image shape metadata disagree, so patches cannot be correctly unflattened.

Source

Thrown at python/sglang/srt/models/siglip2.py:95

        Returns:
            (1, total_tokens, embed_dim) packed embeddings.
        """
        assert spatial_shapes.device.type == "cpu", (
            "Expected `spatial_shapes` on CPU to avoid device-to-host sync in "
            "variable-length packing."
        )

        if pixel_values_packed.dim() == 3:
            assert pixel_values_packed.shape[0] == 1
            pixel_values_flat = pixel_values_packed[0]
        else:
            pixel_values_flat = pixel_values_packed

        lengths = (spatial_shapes[:, 0] * spatial_shapes[:, 1]).to(dtype=torch.int64)
        lengths_list = lengths.tolist()
        total_tokens = int(sum(lengths_list))
        if total_tokens != pixel_values_flat.shape[0]:
            raise ValueError(
                "Packed pixel_values token count does not match spatial_shapes: "
                f"{pixel_values_flat.shape[0]} vs {total_tokens}."
            )

        target_dtype = self.patch_embedding.weight.dtype
        patch_embeds = self.patch_embedding(pixel_values_flat.to(dtype=target_dtype))

        positional_embeddings = self.position_embedding.weight.reshape(
            self.position_embedding_size, self.position_embedding_size, -1
        )
        packed_pos_embeds = self.resize_positional_embeddings_packed(
            positional_embeddings,
            spatial_shapes,
            lengths_list=lengths_list,
        )

        embeddings = patch_embeds + packed_pos_embeds
        return embeddings.unsqueeze(0)

View on GitHub (pinned to 0132848349)

Solutions

  1. Regenerate pixel_values and spatial_shapes with the same processor/preprocessing pass so they stay consistent
  2. Debug-print sum(spatial_shapes[:,0]*spatial_shapes[:,1]) vs pixel_values.shape[0] to find which item diverges
  3. If packing multiple images, ensure spatial_shapes has one row per image and lengths sum to the packed token count

Example fix

# before
pixel_values = preprocess(img)               # shapes from another config
# after
out = processor(images=img, return_spatial_shapes=True)
pixel_values, spatial_shapes = out.pixels, out.shapes  # same pass
Defensive patterns

Strategy: validation

Validate before calling

lens = (spatial_shapes[:,0]*spatial_shapes[:,1]).sum().item()
assert pixel_values.shape[0] == lens, (pixel_values.shape[0], lens)

Prevention

When it happens

Trigger: Feeding packed pixel_values whose rows != sum(spatial_shapes[:,0]*spatial_shapes[:,1]) — e.g. preprocessing produced shapes for a different image set, wrong patch size, or channel/format mismatch after flattening.

Common situations: Custom multimodal preprocessing pipelines for siglip2-based VLMs, resizing images differently than the processor that generated spatial_shapes, or concatenating pixel_values from multiple items without merging spatial_shapes accordingly.

Related errors


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