{"record":{"id":"7d3530b3e2699d37","repo":"sgl-project/sglang","slug":"index-buffer-transfer-expects-page-aligned-indices","errorCode":null,"errorMessage":"Index buffer transfer expects page-aligned indices for DSA.","messagePattern":"Index buffer transfer expects page-aligned indices for DSA\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/mem_cache/pool_host/dsa.py","lineNumber":209,"sourceCode":"        self.staging_buffer = torch.empty(\n            (\n                staging_page_capacity,\n                self.layer_num,\n                1,\n                self.indexer_page_stride_size,\n            ),\n            dtype=self.indexer_dtype,\n            device=self.device_pool.device,\n        )\n\n    def get_hybrid_pool_buffer(self):\n        return [self.index_k_with_scale_buffer]\n\n    def _get_indexer_page_indices(self, host_indices, device_indices):\n        if host_indices.numel() == 0:\n            return host_indices, device_indices\n        if host_indices.numel() % self.page_size != 0:\n            raise ValueError(\n                \"Index buffer transfer expects page-aligned indices for DSA.\"\n            )\n        host_page_indices = (\n            host_indices.reshape(-1, self.page_size)[:, 0] // self.page_size\n        )\n        device_page_indices = (\n            device_indices.reshape(-1, self.page_size)[:, 0] // self.page_size\n        )\n        return host_page_indices, device_page_indices\n\n    def load_to_device_per_layer(\n        self,\n        device_pool,\n        host_indices,\n        device_indices,\n        layer_id,\n        io_backend,\n        *,","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/mem_cache/pool_host/dsa.py#L191-L227","documentation":"DSA index buffer transfers move whole pages between host and device, so the flat token indices must be a multiple of page_size. _get_indexer_page_indices validates this and converts token indices to page indices by reshape(-1, page_size)[:, 0] // page_size.","triggerScenarios":"Calling load_to_device_per_layer / backup_from_device_all_layer with host_indices whose length is not divisible by the DSA page size (partial page at the end of the batch).","commonSituations":"Custom or edge-case eviction/writeback paths that batch a non-page-aligned number of tokens; page_size misconfiguration where indices were computed with a different page size than the pool's.","solutions":["Ensure transfer batches are padded/rounded up to whole pages before calling transfer APIs","Verify the page_size used to generate indices matches the pool's page_size","Fix the calling scheduler/evictor to never emit partial pages"],"exampleFix":"# before\nhost_indices = torch.tensor([0,1,2])  # page_size=4\n# after\nhost_indices = host_indices[: len(host_indices) // page_size * page_size]  # drop partial page","handlingStrategy":"validation","validationCode":"assert host_indices.numel() % page_size == 0","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Round transfer batches to whole pages","Keep a single source of truth for page_size between index generation and the pool"],"tags":["dsa-hicache","page-alignment","transfer"],"backgroundTag":"alignment-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}