sgl-project/sglang · error · ValueError

subblock_sparse_query_block_mask must be a tensor

Error message

subblock_sparse_query_block_mask must be a tensor

What it means

subblock_sparse_query_block_mask, when not None, must be a torch.Tensor — the downstream block-sparse attention API consumes tensor masks only. Passing e.g. a numpy array, list, or a BlockMask object raises this.

Source

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

        )

        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
        local_seq_len = seq_len
        if sp_ws > 1:
            if seq_len % sp_ws:
                raise ValueError(
                    f"packed seq_len {seq_len} not divisible by the combined "
                    f"sequence-parallel world size {sp_ws} "
                    f"(ulysses={ulysses_ws} x ring={ring_ws})"

View on GitHub (pinned to 0132848349)

Solutions

  1. Convert with torch.as_tensor(mask, device=x.device) before passing
  2. Or pass None if no subblock sparse query mask is needed for this task

Example fix

// before
model(x=packed, subblock_sparse_query_block_mask=np_mask, ...)
// after
model(x=packed, subblock_sparse_query_block_mask=torch.as_tensor(np_mask, device=packed.device), ...)
Defensive patterns

Strategy: type-guard

Validate before calling

if subblock_sparse_query_block_mask is not None:
    subblock_sparse_query_block_mask = torch.as_tensor(subblock_sparse_query_block_mask, device=x.device)

Type guard

def is_tensor_mask(m) -> bool:
    return m is None or torch.is_tensor(m)

Prevention

When it happens

Trigger: Providing a numpy ndarray, nested list, or a flash-attention BlockMask-style object where a dense tensor query block mask is expected.

Common situations: Adapting masks produced by another attention library (nested lists from Python scheduling code, numpy from preprocessing) without converting to torch.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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