diff --git a/python/sglang/srt/mem_cache/unified_memory_pool.py b/python/sglang/srt/mem_cache/unified_memory_pool.py index 0d8acc7b1..194a8a91d 100644 --- a/python/sglang/srt/mem_cache/unified_memory_pool.py +++ b/python/sglang/srt/mem_cache/unified_memory_pool.py @@ -1424,12 +1424,18 @@ class UnifiedSWAKVPool(SWAKVPool): "attach_allocators" ) ps = self._swa_allocator.page_size + # Tombstone-safety clamp, matching MultiEndedAllocator.translate_kv_loc: + # a tombstoned v2p entry (-1) must not reach the caller as a negative + # loc. Clamp to 0 routes it to the reserved padding sink instead. if ps == 1: - return self._swa_allocator.virtual_to_physical[kv_indices].to(torch.int32) - virt_pages = kv_indices // ps - offsets = kv_indices % ps - swa_phys_pages = self._swa_allocator.virtual_to_physical[virt_pages] - return (swa_phys_pages * ps + offsets).to(torch.int32) + swa_locs = self._swa_allocator.virtual_to_physical[kv_indices] + else: + virt_pages = kv_indices // ps + offsets = kv_indices % ps + swa_phys_pages = self._swa_allocator.virtual_to_physical[virt_pages] + # Tombstoned page: -1 * ps + offset lands in [-ps, -1]. + swa_locs = swa_phys_pages * ps + offsets + return swa_locs.clamp(min=0).to(torch.int32) def get_state_buf_infos(self): return self.swa_kv_pool.get_contiguous_buf_infos()