sgl-project/sglang · error · ValueError

dim {dim} must be divisible by head_dim {head_dim}.

Error message

dim {dim} must be divisible by head_dim {head_dim}.

What it means

The decoder's neighborhood-attention block splits `dim` into `heads = dim // head_dim` attention heads; if dim is not an exact multiple of head_dim the reshape is impossible, so __init__ validates it up front.

Source

Thrown at python/sglang/multimodal_gen/runtime/models/decoders/ltx_2_5_diffusion_decoder.py:374

                        "platform; falling back to eager"
                    ),
                )
        return self._apply_rope(query, tables), self._apply_rope(key, tables)


class LTX2VideoVaeNeighborhoodAttention(nn.Module):
    """3D neighborhood attention over a channels-last `(B, T, H, W, C)` volume."""

    def __init__(
        self,
        dim: int,
        kernel_size: tuple[int, int, int],
        head_dim: int = 64,
        rope_base: float = 10000.0,
    ) -> None:
        super().__init__()
        if dim % head_dim != 0:
            raise ValueError(f"dim {dim} must be divisible by head_dim {head_dim}.")
        self.heads = dim // head_dim
        self.head_dim = head_dim
        self.kernel_size = tuple(kernel_size)
        self.scale = head_dim**-0.5

        self.to_q = nn.Linear(dim, dim, bias=True)
        self.to_k = nn.Linear(dim, dim, bias=True)
        self.to_v = nn.Linear(dim, dim, bias=True)
        self.to_out = nn.ModuleList([nn.Linear(dim, dim, bias=True), nn.Dropout(0.0)])
        self.norm_q = nn.RMSNorm(head_dim, eps=1e-6)
        self.norm_k = nn.RMSNorm(head_dim, eps=1e-6)
        self.rope = LTX2VideoVaeRotaryPosEmbed3D(head_dim, base=rope_base)

    def project_qkv(
        self, hidden_states: torch.Tensor
    ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
        """Q/K/V as `(B, T, H, W, heads, head_dim)`: normed, query pre-scaled, rotated.

View on GitHub (pinned to 0132848349)

Solutions

  1. Align stage channel dims to be multiples of head_dim (e.g. multiples of 64)
  2. Or pass head_dim that divides dim exactly (e.g. head_dim=50 for dim=1000)
  3. Re-check the full decoder_stage_channels list against the shipped arch defaults

Example fix

# before
block = NeighborhoodAttentionBlock(dim=1000, kernel_size=(3,3,3), head_dim=64)
# after
block = NeighborhoodAttentionBlock(dim=1024, kernel_size=(3,3,3), head_dim=64)
Defensive patterns

Strategy: validation

Validate before calling

if dim % head_dim != 0:
    raise ValueError(f"dim {dim} not divisible by head_dim {head_dim}")

Type guard

def dims_aligned(dim: int, head_dim: int) -> bool:
    return head_dim > 0 and dim % head_dim == 0

Try / catch

try:
    block = NeighborhoodAttentionBlock(dim=dim, kernel_size=k, head_dim=head_dim)
except ValueError:
    head_dim = next(h for h in (64, 32, 16, 8) if dim % h == 0)
    block = NeighborhoodAttentionBlock(dim=dim, kernel_size=k, head_dim=head_dim)

Prevention

When it happens

Trigger: Constructing the attention block with dim not divisible by head_dim — e.g. dim=1000 with head_dim=64, or a stage_channels value from arch config that doesn't align with the default head_dim=64.

Common situations: Customizing decoder stage widths without adjusting head_dim; mixing config values from a different model revision where dims changed; typos in width lists.

Related errors


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