{"record":{"id":"a6e7913e38a88fef","repo":"sgl-project/sglang","slug":"radixkey-index-out-of-range-idx","errorCode":null,"errorMessage":"RadixKey index out of range: {idx}","messagePattern":"RadixKey index out of range: (.+?)","errorType":"exception","errorClass":"IndexError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/mem_cache/radix_cache.py","lineNumber":124,"sourceCode":"    def __iter__(self) -> Iterator:\n        t = self.token_ids\n        n = self._raw_len()\n        if self.is_bigram:\n            for i in range(n - 1 if n > 0 else 0):\n                yield (t[i], t[i + 1])\n        elif n == len(t):\n            yield from t\n        else:\n            for i in range(n):\n                yield t[i]\n\n    def __getitem__(self, idx: Union[int, slice]) -> RadixKey:\n        # Normalize int -> 1-element slice so the rest handles one shape.\n        if isinstance(idx, int):\n            if idx < 0:\n                idx += len(self)\n            if idx < 0 or idx >= len(self):\n                raise IndexError(f\"RadixKey index out of range: {idx}\")\n            idx = slice(idx, idx + 1)\n        start, stop, step = idx.indices(len(self))\n        if step != 1:\n            raise ValueError(\"RadixKey slice step must be 1\")\n\n        if self.is_bigram:\n            # bigrams [start, stop) span raw tokens [start, stop + 1);\n            # empty slice -> empty raw tokens (not a dangling boundary token).\n            raw = self.token_ids[start : stop + 1] if stop > start else array(\"q\")\n            return RadixKey(\n                raw,\n                self.extra_key,\n                is_bigram=True,\n                cache_salt=self.cache_salt,\n            )\n        return RadixKey(\n            self.token_ids[start:stop],\n            self.extra_key,","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/mem_cache/radix_cache.py#L106-L142","documentation":"RadixKey.__getitem__ raises IndexError when an integer index falls outside [0, len(key)) after negative-index normalization. RadixKey is the logical-unit key wrapper over token ids in SGLang's radix cache, so out-of-range slicing usually means caller code assumed a different key length (e.g. raw token count vs bigram count).","triggerScenarios":"Calling key[i] or key[i:j] on a RadixKey with i >= len(key), or a negative index whose magnitude exceeds len(key) (e.g. key[-5] on a length-2 key). Typically from prefix-matching code that computed an offset from token_ids length while the key is in bigram mode where len differs by 1.","commonSituations":"Off-by-one bugs when mixing raw token indices with logical (page/bigram) units; slicing with cached lengths after a key was truncated; porting code from the old array('q') token_ids interface to RadixKey.","solutions":["Check len(key) before indexing and clamp: idx = min(idx, len(key) - 1)","Use non-negative indices or ensure negative indices satisfy -len(key) <= idx < 0","For bigram keys, remember len is token count - 1 and derive indices from len(key), not from the raw token array"],"exampleFix":"# before\nsub = key[len(token_ids) - 1]\n# after\nsub = key[min(len(token_ids) - 1, len(key) - 1)]","handlingStrategy":"validation","validationCode":"n = len(key)\nif not (-n <= idx < n):\n    raise ValueError(f\"index {idx} out of range for RadixKey of len {n}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always derive indices from len(key), never from the raw token_ids length","Clamp indices before slicing","Write unit tests hitting both boundary indices 0 and len-1"],"tags":["radix-cache","index-error","off-by-one","prefix-cache"],"backgroundTag":"index-out-of-range","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}