sgl-project/sglang · error · ValueError

f"Unsupported patch_size type: {type(patch_size)}"

Error message

f"Unsupported patch_size type: {type(patch_size)}"

What it means

The visual embedding layer's __init__ accepts patch_size only as an int (converted to a 3-tuple) or a 3-element sequence. Any other type — a string, a single float, a dict, or a tuple/list of length != 3 — reaches the else branch and raises this ValueError.

Source

Thrown at python/sglang/multimodal_gen/runtime/layers/visual_embedding.py:133

    def __init__(
        self,
        patch_size=(1, 2, 2),
        in_chans=384,
        embed_dim=2048,
        bias=True,
        dtype=None,
        prefix: str = "",
    ):
        super().__init__()
        del prefix
        if isinstance(patch_size, list | tuple):
            if len(patch_size) != 3:
                raise ValueError(
                    f"patch_size must have length 3, got {len(patch_size)}"
                )
            patch_size = tuple(patch_size)
        else:
            raise ValueError(f"Unsupported patch_size type: {type(patch_size)}")

        self.patch_size = patch_size
        pt, ph, pw = self.patch_size
        self.in_features = in_chans * pt * ph * pw
        self.proj = nn.Linear(self.in_features, embed_dim, bias=bias, dtype=dtype)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if x.dim() != 5:
            raise ValueError(
                f"Expected camera embedding shape [B, C, F, H, W], got {tuple(x.shape)}"
            )

        bsz, channels, frames, height, width = x.shape
        pt, ph, pw = self.patch_size
        if (frames % pt) != 0 or (height % ph) != 0 or (width % pw) != 0:
            raise ValueError(
                f"Input shape {tuple(x.shape)} must be divisible by patch_size {self.patch_size}"
            )

View on GitHub (pinned to 0132848349)

Solutions

  1. Pass patch_size as an int (e.g. 16, meaning (16,16,16)) or a length-3 sequence of ints like (2,16,16) (temporal, height, width)
  2. If the value comes from a config file, parse it before construction: json.loads(value) if isinstance(value, str)
  3. Add a sanity check on the config: assert isinstance(patch_size, (int, list, tuple)) and len(patch_size) in (1, 3)

Example fix

# before
layer = VisualEmbedding(patch_size="2x16x16", ...)
# after
layer = VisualEmbedding(patch_size=(2, 16, 16), ...)
Defensive patterns

Strategy: validation

Validate before calling

def coerce_patch_size(v):
    if isinstance(v, int):
        return (v, v, v)
    if isinstance(v, (list, tuple)) and len(v) == 3:
        return tuple(int(x) for x in v)
    raise TypeError(f"bad patch_size: {v!r}")

patch_size = coerce_patch_size(model_config['patch_size'])

Type guard

def is_valid_patch_size(v) -> bool:
    return isinstance(v, int) or (
        isinstance(v, (list, tuple)) and len(v) == 3 and all(isinstance(x, int) for x in v)
    )

Prevention

When it happens

Trigger: Constructing the camera/projector embedding layer with patch_size passed as e.g. "2x16x16" (a string), 16.0 (a float), a dict from a JSON config, or a 2-element tuple like (16, 16). Only int or length-3 list/tuple of ints is accepted.

Common situations: Loading a model config from JSON/YAML where patch_size got serialized as a string or nested list; hand-written model definitions copying HF config strings like patch_size=(1,16) with a typo; config round-tripping converting tuples to strings.

Related errors


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