{"record":{"id":"1ff52d70f3dd5946","repo":"sgl-project/sglang","slug":"minimax-h3-initial-video-rows-must-be-a-rank-2-ten","errorCode":null,"errorMessage":"MiniMax H3 initial_video_rows must be a rank-2 tensor","messagePattern":"MiniMax H3 initial_video_rows must be a rank-2 tensor","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/latent_preparation.py","lineNumber":53,"sourceCode":"        batches: list[Req],\n        server_args: ServerArgs,\n    ) -> list[Req]:\n        \"\"\"Preserve H3's independent per-modality RNG streams per request.\"\"\"\n        return [self(batch, server_args) for batch in batches]\n\n    @staticmethod\n    def _publish_native_latent_state(batch: Req) -> None:\n        from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.constants import (\n            MINIMAX_H3_DENOISE_STATE_EXTRA_KEY,\n        )\n\n        state = batch.extra.get(MINIMAX_H3_DENOISE_STATE_EXTRA_KEY)\n        if not isinstance(state, dict):\n            raise ValueError(\"MiniMax H3 denoise state must be a mapping\")\n        video_rows = state.get(\"initial_video_rows\")\n        audio_rows = state.get(\"initial_audio_rows\")\n        if not isinstance(video_rows, torch.Tensor) or video_rows.ndim != 2:\n            raise ValueError(\"MiniMax H3 initial_video_rows must be a rank-2 tensor\")\n        if not isinstance(audio_rows, torch.Tensor) or audio_rows.ndim != 2:\n            raise ValueError(\"MiniMax H3 initial_audio_rows must be a rank-2 tensor\")\n\n        latent_t = int(state[\"latent_t\"])\n        latent_h = int(state[\"latent_h\"])\n        latent_w = int(state[\"latent_w\"])\n        audio_t = int(state[\"audio_t\"])\n        batch.latents = video_rows\n        batch.audio_latents = audio_rows\n        batch.raw_latent_shape = (1, 24, latent_t, latent_h, latent_w)\n        batch.raw_audio_latent_shape = (2, 32, audio_t)\n\n    def _prepare_denoise_state_from_plan(self, batch: Req, plan) -> None:\n        \"\"\"Direct initial-noise materialization (t2va recipe):\n        torch.Generator().manual_seed(seed); video rows drawn first,\n        then audio rows, CPU fp32. Every task consumes the final latent grid\n        frozen by the pre-queue shape resolver.\"\"\"\n        from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.minimax_h3.constants import (","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/minimax_h3/stages/latent_preparation.py#L35-L71","documentation":"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]).","triggerScenarios":"_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.","commonSituations":"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.","solutions":["Ensure initial_video_rows is a rank-2 torch tensor of shape [video_rows_n, 96]","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)","Prefer letting _prepare_denoise_state_from_plan generate the noise from the resolved plan instead of injecting manually"],"exampleFix":"// before\nstate[\"initial_video_rows\"] = video_noise.unsqueeze(0)  # rank 3\n// after\nstate[\"initial_video_rows\"] = video_noise  # rank-2 [N, 96]","handlingStrategy":"type-guard","validationCode":"rows = state.get(\"initial_video_rows\")\nassert isinstance(rows, torch.Tensor) and rows.ndim == 2 and rows.shape[1] == 96, rows.shape if isinstance(rows, torch.Tensor) else type(rows)","typeGuard":"def is_rank2_tensor(x) -> bool:\n    return isinstance(x, torch.Tensor) and x.ndim == 2","tryCatchPattern":null,"preventionTips":["Inject denoise state only with rank-2 [N, 96] tensors","Squeeze stray batch dims before storing tensors in batch.extra"],"tags":["minimax-h3","tensor-shape","batch-state"],"backgroundTag":"tensor-rank-validation","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}