sgl-project/sglang · error · ValueError

{name} must be on the same device as block sparse tensors

Error message

{name} must be on the same device as block sparse tensors

What it means

Raised when an auxiliary metadata tensor (e.g. dq_write_order) lives on a different device than the mask block count tensor. All block-sparse tensors must be co-located because the kernel treats them as one bundle.

Source

Thrown at python/sglang/kernels/ops/attention/flash_attn/cute/block_sparsity.py:283

        idx, expected_index_shape, f"{name}_block_idx", context, hint
    )
    return expanded_cnt, expanded_idx


def _check_and_expand_metadata_tensor(
    name: str,
    tensor: torch.Tensor | None,
    expected_shape: Tuple[int, ...],
    context: str | None,
    hint: str | Callable[[], str] | None,
    device: torch.device,
) -> torch.Tensor | None:
    if tensor is None:
        return None
    if tensor.dtype != torch.int32:
        raise ValueError(f"{name} must have dtype torch.int32")
    if tensor.device != device:
        raise ValueError(f"{name} must be on the same device as block sparse tensors")
    if not tensor.is_cuda:
        raise ValueError(f"{name} must live on CUDA")
    return _expand_sparsity_tensor(tensor, expected_shape, name, context, hint)


def get_block_sparse_expected_shapes(
    batch_size: int,
    num_head: int,
    seqlen_q: int,
    seqlen_k: int,
    m_block_size: int,
    n_block_size: int,
    q_stage: int,
) -> Tuple[Tuple[int, int, int], Tuple[int, int, int, int]]:
    """Return (expected_count_shape, expected_index_shape) for block sparse normalization."""
    m_block_size_effective = q_stage * m_block_size
    expected_m_blocks = ceildiv(seqlen_q, m_block_size_effective)
    expected_n_blocks = ceildiv(seqlen_k, n_block_size)

View on GitHub (pinned to 0132848349)

Solutions

  1. Move metadata to mask_cnt.device: dq_write_order = dq_write_order.to(mask_cnt.device)
  2. Standardize all tensors to torch.cuda.current_device() before building BlockSparseTensorsTorch

Example fix

// before
order = order.to('cuda:0'); mask = mask.to('cuda:1')
// after
order = order.to(mask_cnt.device)
Defensive patterns

Strategy: validation

Validate before calling

if dq_write_order is not None:
    dq_write_order = dq_write_order.to(mask_block_cnt.device)

Prevention

When it happens

Trigger: dq_write_order on cuda:1 (or CPU) while mask_block_cnt is on cuda:0 when calling normalize_block_sparse_tensors.

Common situations: Multi-GPU (TP/EP) runs where metadata was generated on a different rank's device, or CPU-cached metadata reused after moving the mask tensors.

Related errors


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