sgl-project/sglang · error · ValueError
video rows {int(rows.shape[0])} must be divisible by t*h*w {
Error message
video rows {int(rows.shape[0])} must be divisible by t*h*w {rows_per_sample} for latent_shape={list(latent_shape)} What it means
The unpatchify path requires the total number of token rows to be a whole multiple of t*h*w (rows per video sample implied by latent_shape). A remainder means rows cannot be evenly reshaped into per-frame patch grids, indicating a batch/row-count inconsistency between the token tensor and the declared latent shape.
Source
Thrown at python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/packed_tokens.py:64
*,
latent_shape: Sequence[int],
patch_size: Sequence[int],
) -> torch.Tensor:
"""Unpack DiT video token rows into SGLang latent [B,C,T,H,W]."""
_rank(rows, "video token rows", 2)
t, h, w, channel = _int_tuple(latent_shape, "latent_shape", 4)
pt, ph, pw = _int_tuple(patch_size, "patch_size", 3)
expected_dim = pt * ph * pw * channel
if int(rows.shape[-1]) != expected_dim:
raise ValueError(
f"video token dim {int(rows.shape[-1])} != patch volume * channel "
f"{expected_dim} for latent_shape={list(latent_shape)}, "
f"patch_size={[pt, ph, pw]}"
)
rows_per_sample = t * h * w
if int(rows.shape[0]) % rows_per_sample:
raise ValueError(
f"video rows {int(rows.shape[0])} must be divisible by t*h*w "
f"{rows_per_sample} for latent_shape={list(latent_shape)}"
)
packed = rows.reshape(-1, t, h, w, channel, pt, ph, pw)
latent = torch.einsum("nthwcrpq->nctrhpwq", packed)
return latent.reshape(-1, channel, t * pt, h * ph, w * pw).contiguous()
def minimax_h3_unpack_audio_tokens(
rows: torch.Tensor,
*,
audio_t: int,
audio_channel: int,
) -> torch.Tensor:
"""Unpack DiT audio token rows into SGLang audio VAE latent [C,latent_dim,T]."""
_rank(rows, "audio token rows", 2)
audio_t = int(audio_t)View on GitHub (pinned to 0132848349)
Solutions
- Split the rows buffer per video (using the layout's block slices) and unpatchify each with its own latent_shape.
- Ensure latent_shape's t,h,w exactly match the frames/resolution the rows were generated from.
- Recompute latent_shape from the plan rather than caching it across requests.
Example fix
# before
latent = minimax_h3_unpatchify_video_tokens(all_rows, latent_shape=one_clip_shape, patch_size=patch)
# after
for sl, shape in zip(block_slices, block_latent_shapes):
latent_i = minimax_h3_unpatchify_video_tokens(all_rows[sl], latent_shape=shape, patch_size=patch) Defensive patterns
Strategy: validation
Validate before calling
t, h, w, _ = latent_shape
rows_per_sample = t * h * w
assert rows.shape[0] % rows_per_sample == 0, f"row count {rows.shape[0]} not a multiple of {rows_per_sample}" Type guard
def rows_partition_cleanly(rows, latent_shape) -> bool:
t, h, w, _ = latent_shape
return rows.shape[0] % (t * h * w) == 0 Prevention
- Unpatchify per video block using the layout's slices, not the concatenated buffer.
- Derive latent_shape from the current plan/request rather than caching it.
When it happens
Trigger: Passing rows for 5.5 samples' worth of grids relative to latent_shape, e.g. rows.shape[0]=1000 with t*h*w=256 (1000%256!=0); commonly concatenating reference and target video rows but declaring latent_shape for only one video.
Common situations: Concatenating multiple videos' rows (hybrid ref+target layouts) while unpatchifying with a single clip's latent_shape; dropped/duplicated rows during scheduling or attention masking; a stale latent_shape after changing resolution or frame count.
Related errors
- video token dim {int(rows.shape[-1])} != patch volume * chan
- MiniMax-H3 adaln_t_table must have shape [N, D] with N >= 2,
- {name} must be rank {rank}, got shape={list(tensor.shape)}
- video latent spatial/time dims must be divisible by patch_si
- `dt_bias` must have {HV * K} elements (got {dt_bias.numel()}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/6febd28b2e502b0b.
Report an issue: GitHub.