sgl-project/sglang · error · ValueError

MiniMax H3 initial_video_rows must be a rank-2 tensor

Error message

MiniMax H3 initial_video_rows must be a rank-2 tensor

What it means

After confirming the denoise state is a mapping, the stage validates that state['initial_video_rows'] is a torch.Tensor with exactly 2 dimensions. The error means the video noise rows entry is missing (None), not a tensor, or has a rank other than 2 (the expected shape is [video_rows_n, 96]).

Source

Thrown at python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/latent_preparation.py:53

        batches: list[Req],
        server_args: ServerArgs,
    ) -> list[Req]:
        """Preserve H3's independent per-modality RNG streams per request."""
        return [self(batch, server_args) for batch in batches]

    @staticmethod
    def _publish_native_latent_state(batch: Req) -> None:
        from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.constants import (
            MINIMAX_H3_DENOISE_STATE_EXTRA_KEY,
        )

        state = batch.extra.get(MINIMAX_H3_DENOISE_STATE_EXTRA_KEY)
        if not isinstance(state, dict):
            raise ValueError("MiniMax H3 denoise state must be a mapping")
        video_rows = state.get("initial_video_rows")
        audio_rows = state.get("initial_audio_rows")
        if not isinstance(video_rows, torch.Tensor) or video_rows.ndim != 2:
            raise ValueError("MiniMax H3 initial_video_rows must be a rank-2 tensor")
        if not isinstance(audio_rows, torch.Tensor) or audio_rows.ndim != 2:
            raise ValueError("MiniMax H3 initial_audio_rows must be a rank-2 tensor")

        latent_t = int(state["latent_t"])
        latent_h = int(state["latent_h"])
        latent_w = int(state["latent_w"])
        audio_t = int(state["audio_t"])
        batch.latents = video_rows
        batch.audio_latents = audio_rows
        batch.raw_latent_shape = (1, 24, latent_t, latent_h, latent_w)
        batch.raw_audio_latent_shape = (2, 32, audio_t)

    def _prepare_denoise_state_from_plan(self, batch: Req, plan) -> None:
        """Direct initial-noise materialization (t2va recipe):
        torch.Generator().manual_seed(seed); video rows drawn first,
        then audio rows, CPU fp32. Every task consumes the final latent grid
        frozen by the pre-queue shape resolver."""
        from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.constants import (

View on GitHub (pinned to 0132848349)

Solutions

  1. Ensure initial_video_rows is a rank-2 torch tensor of shape [video_rows_n, 96]
  2. If it has an extra leading dim of size 1, squeeze it; if it's numpy/list, convert with torch.as_tensor(...).reshape(N, -1)
  3. Prefer letting _prepare_denoise_state_from_plan generate the noise from the resolved plan instead of injecting manually

Example fix

// before
state["initial_video_rows"] = video_noise.unsqueeze(0)  # rank 3
// after
state["initial_video_rows"] = video_noise  # rank-2 [N, 96]
Defensive patterns

Strategy: type-guard

Validate before calling

rows = state.get("initial_video_rows")
assert isinstance(rows, torch.Tensor) and rows.ndim == 2 and rows.shape[1] == 96, rows.shape if isinstance(rows, torch.Tensor) else type(rows)

Type guard

def is_rank2_tensor(x) -> bool:
    return isinstance(x, torch.Tensor) and x.ndim == 2

Prevention

When it happens

Trigger: _publish_native_latent_state finds state['initial_video_rows'] that is None, a non-tensor (e.g. numpy array or list), or a tensor with ndim != 2 — e.g. saved with an extra batch dimension or reshaped to rank 3.

Common situations: Manually injecting or checkpointing denoise state where the video noise tensor was stored with an unsqueezed dim, converted to numpy, or sliced incorrectly; version changes that altered the noise layout contract.

Related errors


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