sgl-project/sglang · error · ValueError

inverse_indices must be [{seq_len}], got {list(inverse_indic

Error message

inverse_indices must be [{seq_len}], got {list(inverse_indices.shape)}

What it means

inverse_indices must be length S (the full packed sequence length) so the model can un-permute/sort outputs back to the original token order. A wrong-length tensor would gather out-of-bounds.

Source

Thrown at python/sglang/multimodal_gen/runtime/models/dits/minimax_h3.py:2448

        max_seqlen = int(self._psp_field(psp, "packed_seq_params", "max_seqlen_q"))
        refiner_psp = _required_kwarg(kwargs, "refiner_packed_seq_params")
        refiner_cu = self._psp_field(
            refiner_psp, "refiner_packed_seq_params", "cu_seqlens_q"
        ).to(torch.int32)
        refiner_max = int(
            self._psp_field(refiner_psp, "refiner_packed_seq_params", "max_seqlen_q")
        )

        if x.dim() != 3 or x.shape[0] != 1:
            raise ValueError(f"x must be [1, S, C], got {list(x.shape)}")
        seq_len = int(x.shape[1])
        if token_tags is not None and token_tags.shape[0] != seq_len:
            raise ValueError(
                "token_tags must cover the full packed sequence "
                f"({seq_len}), got {token_tags.shape[0]}."
            )
        if inverse_indices.shape[0] != seq_len:
            raise ValueError(
                f"inverse_indices must be [{seq_len}], got {list(inverse_indices.shape)}"
            )
        device = x.device
        if subblock_sparse_query_block_mask is not None and not isinstance(
            subblock_sparse_query_block_mask, torch.Tensor
        ):
            raise ValueError("subblock_sparse_query_block_mask must be a tensor")
        self._resolve_attention_backend_once()

        # Row split is 2D: ring first (an outer, contiguous ring_chunk_len
        # slice of the packed sequence), Ulysses second (an inner slice
        # within this rank's ring chunk). Only Ulysses shards heads inside
        # attention -- ring instead ring-rotates each rank's local KV chunk
        # and online-softmax merges partial outputs (see
        # _minimax_h3_attention_core_impl), so it has no head constraint.
        ulysses_ws, ulysses_rank = get_ulysses_ctx()
        ring_ws, ring_rank = get_ring_ctx()
        sp_ws = ulysses_ws * ring_ws

View on GitHub (pinned to 0132848349)

Solutions

  1. Recompute inverse_indices = torch.argsort(sort_indices) over the same S tokens that form x
  2. Pass global full-length indices; the model slices them per rank itself
  3. Assert inverse_indices.shape[0] == x.shape[1] before forward

Example fix

// before
model(x=packed, inverse_indices=local_idx, ...)
// after
sort_idx = torch.argsort(keys, stable=True)
inv_idx = torch.argsort(sort_idx)
model(x=packed, inverse_indices=inv_idx, ...)
Defensive patterns

Strategy: validation

Validate before calling

assert inverse_indices.shape[0] == x.shape[1], (inverse_indices.shape, x.shape)

Prevention

When it happens

Trigger: Passing inverse_indices from torch.argsort computed over a different sequence, or rank-local (already sharded) indices instead of global packed indices.

Common situations: Reusing sort indices from before packing changes; sharding/slicing the indices for sequence parallelism before the model expects to do its own slicing at line 2540 region.

Related errors


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