sgl-project/sglang · error · ValueError

out, max_logits and lse must not alias each other

Error message

out, max_logits and lse must not alias each other

What it means

The sparse MLA prefill kernel writes out, max_logits and lse through three independent pointers; if any two alias the same storage, one write would clobber another's results. The wrapper compares data_ptr() of the three buffers and rejects any overlap before launch.

Source

Thrown at python/sglang/kernels/ops/attention/sparse_mla_q8kv8_prefill_sm90.py:460

        _check_out_buffer(out, "out", (s_q, h_q, d_v), torch.bfloat16, device)

    if max_logits is None:
        max_logits = torch.empty(s_q, h_q, dtype=torch.float32, device=device)
    else:
        _check_out_buffer(max_logits, "max_logits", (s_q, h_q), torch.float32, device)

    if lse is None:
        lse = torch.empty(s_q, h_q, dtype=torch.float32, device=device)
    else:
        _check_out_buffer(lse, "lse", (s_q, h_q), torch.float32, device)

    # The three output tensors are written independently by the kernel; any
    # aliasing among them would corrupt results, so reject it explicitly.
    out_ptr = out.data_ptr()
    ml_ptr = max_logits.data_ptr()
    lse_ptr = lse.data_ptr()
    if out_ptr == ml_ptr or out_ptr == lse_ptr or ml_ptr == lse_ptr:
        raise ValueError("out, max_logits and lse must not alias each other")

    cuda_stream = _get_current_stream_raw(q.device.index)

    if attn_sink is not None and topk_length is not None:
        _sparse_mla_q8kv8_prefill_full_op(
            q,
            kv,
            indices,
            q_scale,
            kv_scale,
            attn_sink,
            topk_length,
            out,
            max_logits,
            lse,
            s_q,
            s_kv,
            h_q,

View on GitHub (pinned to 0132848349)

Solutions

  1. Allocate three separate tensors: torch.empty(...) for out, max_logits and lse independently
  2. If slicing a pooled buffer, ensure the byte ranges do not overlap (distinct offsets with sufficient sizes)

Example fix

// before
buf = torch.empty(s_q*h_q*(d_v+2), ...)
out, max_logits, lse = buf[:a], buf[a:b], buf[b:]  # or worse, aliased
// after
out = torch.empty((s_q, h_q, d_v), dtype=torch.bfloat16, device=device)
max_logits = torch.empty((s_q, h_q), dtype=torch.float32, device=device)
lse = torch.empty((s_q, h_q), dtype=torch.float32, device=device)
Defensive patterns

Strategy: validation

Validate before calling

ptrs = {out.data_ptr(), max_logits.data_ptr(), lse.data_ptr()}
assert len(ptrs) == 3, 'output buffers must not alias'

Type guard

def distinct_buffers(*ts) -> bool:
    return len({t.data_ptr() for t in ts}) == len(ts)

Prevention

When it happens

Trigger: Passing caller-provided buffers where, e.g., lse and max_logits were carved from one allocation (out=lse=some_tensor, or overlapping views of one flat buffer), so any pair of data_ptr() values is equal.

Common situations: Pre-allocating one workspace tensor and slicing out the three outputs to save memory, or accidentally passing the same tensor twice when wiring up custom output buffers.

Related errors


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