{"record":{"id":"154617ad323b4ce8","repo":"sgl-project/sglang","slug":"recent-window-tokens-must-be-0-or-none","errorCode":null,"errorMessage":"recent_window_tokens must be >= 0 or None","messagePattern":"recent_window_tokens must be >= 0 or None","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/layers/kvcache/qvg_packed_cache.py","lineNumber":347,"sourceCode":"            local_start_index=0,\n            local_end_index=num_new,\n            visible_local_end=min(self._global_end, self.cache_size),\n            visible_global_end=self._global_end,\n        )\n\n    def _reconstruct(\n        self,\n        current_chunk_start: int,\n        recent_window_tokens: int | None,\n    ) -> tuple[torch.Tensor, torch.Tensor]:\n        \"\"\"Dense visible window = sink prefix ++ rolling recent tail, matching\n        the dense cache's [sink | rolled-recent] buffer content.\"\"\"\n        sink_end = self._sink_end()\n        if recent_window_tokens is None:\n            tail_start = self._tail_start()\n        else:\n            if recent_window_tokens < 0:\n                raise ValueError(\"recent_window_tokens must be >= 0 or None\")\n            tail_start = max(sink_end, current_chunk_start - recent_window_tokens)\n\n        if tail_start <= sink_end:\n            ranges = [(0, self._global_end)]\n        else:\n            ranges = [(0, sink_end), (tail_start, self._global_end)]\n\n        visible_segments: list[tuple[_Segment, int, int]] = []\n        visible_tokens = 0\n        for g_lo, g_hi in ranges:\n            for seg in self._all_segments():\n                a = max(g_lo, seg.g0)\n                b = min(g_hi, seg.g1)\n                if b <= a:\n                    continue\n                visible_segments.append((seg, a - seg.g0, b - seg.g0))\n                visible_tokens += b - a\n","sourceCodeStart":329,"sourceCodeEnd":365,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/layers/kvcache/qvg_packed_cache.py#L329-L365","documentation":"_reconstruct (rebuilding a dense [sink | rolled-recent] view from the packed cache) validates recent_window_tokens: if not None it must be >= 0. Negative windows are meaningless for computing tail_start.","triggerScenarios":"update_and_get_attention_kv on the packed cache with recent_window_tokens < 0 (e.g. -1 sentinel) reaching _reconstruct.","commonSituations":"Config code using -1 to mean 'disabled' colliding with this API's None-for-unlimited convention; arithmetic producing a negative window after subtraction of sink tokens.","solutions":["Use None for unlimited, 0 for sink-only","Clamp: `rw = None if rw is None else max(0, rw)` before the call","Audit config parsing that maps -1 to the window argument"],"exampleFix":"# before\ncache.update_and_get_attention_kv(k, v, recent_window_tokens=-1)\n# after\ncache.update_and_get_attention_kv(k, v, recent_window_tokens=None)","handlingStrategy":"validation","validationCode":"rw = None if recent_window_tokens is None else max(0, int(recent_window_tokens))","typeGuard":"def is_valid_window(w: int | None) -> bool:\\n    return w is None or (isinstance(w, int) and w >= 0)","tryCatchPattern":null,"preventionTips":["Never use -1 as 'disabled' sentinel here","Centralize window-value sanitization in config loading"],"tags":["kv-cache","sliding-window","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}