sgl-project/sglang · error · ValueError

recent_window_tokens must be non-negative or None

Error message

recent_window_tokens must be non-negative or None

What it means

_visible_attention_kv validates that recent_window_tokens, when not None, is a non-negative integer. Negative values would produce a nonsensical sliding window (recent_start before the sink) and are rejected.

Source

Thrown at python/sglang/multimodal_gen/runtime/layers/kvcache/causal_attention_cache.py:376

            [0, sink_end) + [recent_start, updated_local_end)

        Thus ``0`` keeps only sink tokens plus the current chunk.
        ``cache_head_slice`` applies the same token ranges to a subset of KV
        heads.
        """
        if recent_window_tokens is None:
            if self.global_sink_tokens > 0 or self._has_pinned_sink():
                return self._pinned_attention_view(
                    attn_start_index=attn_start_index,
                    updated_local_end=updated_local_end,
                    cache_head_slice=cache_head_slice,
                )
            return self._cache_slice(
                slice(attn_start_index, updated_local_end),
                cache_head_slice=cache_head_slice,
            )
        if recent_window_tokens < 0:
            raise ValueError("recent_window_tokens must be non-negative or None")

        sink_end = min(self._effective_sink_tokens(), updated_local_end)
        recent_start = max(sink_end, local_start_index - recent_window_tokens)
        if recent_start <= sink_end:
            return self._cache_slice(
                slice(0, updated_local_end),
                cache_head_slice=cache_head_slice,
            )

        cache_slices = []
        if sink_end > 0:
            cache_slices.append(slice(0, sink_end))
        if (
            self._has_pinned_sink()
            and self.pinned_start >= sink_end
            and self.pinned_start < recent_start
        ):
            cache_slices.append(

View on GitHub (pinned to 0132848349)

Solutions

  1. Pass None for unlimited window or 0 for sink-only
  2. Sanitize config: `recent_window_tokens = max(0, v) if v is not None else None`
  3. Check where the negative value originates (config default, CLI parse)

Example fix

# before
cache.update_and_get_attention_kv(k, v, recent_window_tokens=-1)
# after
cache.update_and_get_attention_kv(k, v, recent_window_tokens=None)
Defensive patterns

Strategy: validation

Validate before calling

if recent_window_tokens is not None:
    recent_window_tokens = max(0, int(recent_window_tokens))

Type guard

def is_valid_window(w: int | None) -> bool:\n    return w is None or (isinstance(w, int) and w >= 0)

Prevention

When it happens

Trigger: Calling update_and_get_attention_kv (which forwards to _visible_attention_kv) with recent_window_tokens=-1 or any negative int; also triggered by configs mapping a negative window from a CLI/env value.

Common situations: A window config parsed as negative due to a sign flip or 'unlimited' sentinel (-1) convention conflicting with this API; passing 0 meaning 'sink only' is fine, negative is not.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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