sgl-project/sglang · error · ValueError
RadixKey operations require matching extra_key, but got {sel
Error message
RadixKey operations require matching extra_key, but got {self.extra_key=} != {other.extra_key=} What it means
RadixKey binary operations (e.g. match) require both keys to carry identical extra_key metadata, which namespaces cache entries. Mixing keys with different extra_key would compare incomparable cache namespaces, so _check_compatible raises ValueError.
Source
Thrown at python/sglang/srt/mem_cache/radix_cache.py:171
aligned_len = len(self) // page_size * page_size
return self[:aligned_len]
def maybe_to_bigram_view(
self,
is_eagle: bool,
value: Optional[torch.Tensor] = None,
) -> Tuple[RadixKey, Optional[torch.Tensor]]:
# O(1): flip the bigram flag instead of materializing a tuple list.
# value is paired with raw tokens and gets truncated to the bigram count.
if is_eagle and not self.is_bigram:
self.is_bigram = True
if value is not None:
value = value[: len(self)]
return self, value
def _check_compatible(self, other: RadixKey) -> None:
if self.extra_key != other.extra_key:
raise ValueError(
f"RadixKey operations require matching extra_key, but got "
f"{self.extra_key=} != {other.extra_key=}"
)
if self.cache_salt != other.cache_salt:
raise ValueError(
f"RadixKey operations require matching cache_salt, but got "
f"{self.cache_salt=} != {other.cache_salt=}"
)
def match(self, other: RadixKey, page_size: int = 1) -> int:
"""Logical-unit prefix length shared with ``other``. Result is rounded down to ``page_size``."""
self._check_compatible(other)
t0, t1 = self.token_ids, other.token_ids
assert type(t0) is type(t1), (type(t0), type(t1))
n = min(len(t0), len(t1))
# Exponential search for the first diverging token: gallop in doubling
# windows (one C-level slice compare each), then binary-search the windowView on GitHub (pinned to 0132848349)
Solutions
- Build both keys from the same RadixKey.make()/constructor call so extra_key is propagated identically
- Pass the request's extra_key (LoRA id, encoder id) whenever constructing lookup keys, not just insert keys
- Compare extra_key explicitly before calling match if keys come from different sources
Example fix
# before probe = RadixKey(token_ids) # extra_key=None node, val = tree.match_prefix(RadixKey(token_ids, extra_key=req.extra_key)) # after probe = RadixKey(token_ids, extra_key=req.extra_key) node, val = tree.match_prefix(probe)
Defensive patterns
Strategy: validation
Validate before calling
if key_a.extra_key != key_b.extra_key:
raise ValueError("extra_key mismatch; keys belong to different cache namespaces") Type guard
def keys_compatible(a: RadixKey, b: RadixKey) -> bool:
return a.extra_key == b.extra_key and a.cache_salt == b.cache_salt Prevention
- Always construct both insert and lookup keys with the request's extra_key
- Centralize RadixKey construction in one helper so metadata is never dropped
When it happens
Trigger: Calling key_a.match(key_b) where key_a.extra_key != key_b.extra_key — e.g. one key built with lora/interrupt/encoder extras and the other without, or with different LoRA IDs.
Common situations: Serving multiple LoRA adapters or multimodal encoder configs against one radix cache and reusing a lookup key built without the extra metadata; upgrading from a code path where extra_key was ignored to one where it is enforced.
Related errors
- RadixKey slice step must be 1
- RadixKey operations require matching cache_salt, but got {se
- RadixKey index out of range: {idx}
- cache_salt is not supported by the experimental C++ radix tr
- --radix-cache-backend={name!r} is not registered. Registered
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/3f7fe0ce0077de29.
Report an issue: GitHub.