{"record":{"id":"ba4db60e324417e3","repo":"sgl-project/sglang","slug":"logicalhostpool-allocation-must-be-page-aligned-g","errorCode":null,"errorMessage":"LogicalHostPool allocation must be page-aligned, got need_size={need_size}, page_size={self.page_size}","messagePattern":"LogicalHostPool allocation must be page-aligned, got need_size=(.+?), page_size=(.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/mem_cache/memory_pool_host.py","lineNumber":112,"sourceCode":"    def available_size(self):\n        return len(self.free_slots) + self.num_release_slots\n\n    def _merge_release_slots(self):\n        if self.num_release_slots == 0:\n            return\n\n        if len(self.free_slots) == 0 and len(self.release_slots) == 1:\n            self.free_slots = self.release_slots[0]\n        else:\n            self.free_slots = torch.cat([self.free_slots, *self.release_slots])\n\n        self.release_slots = []\n        self.num_release_slots = 0\n\n    @synchronized\n    def alloc(self, need_size: int) -> Optional[torch.Tensor]:\n        if need_size % self.page_size != 0:\n            raise ValueError(\n                \"LogicalHostPool allocation must be page-aligned, \"\n                f\"got need_size={need_size}, page_size={self.page_size}\"\n            )\n        if need_size > self.available_size():\n            return None\n\n        if need_size > len(self.free_slots):\n            self._merge_release_slots()\n\n        select_index = self.free_slots[:need_size]\n        self.free_slots = self.free_slots[need_size:]\n        return select_index\n\n    @synchronized\n    def free(self, indices: torch.Tensor) -> int:\n        if len(indices) % self.page_size != 0:\n            raise ValueError(\n                \"LogicalHostPool free must be page-aligned, \"","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/mem_cache/memory_pool_host.py#L94-L130","documentation":"LogicalHostPool.alloc validates that every allocation request is a multiple of the pool's page_size, since it hands out page-aligned token slots. A non-aligned need_size raises ValueError immediately (before any capacity check).","triggerScenarios":"Calling pool.alloc(need_size) where need_size % page_size != 0, e.g. alloc(len(token_ids)) with a raw sequence length like 37 against page_size=16.","commonSituations":"Callers passing un-padded sequence lengths directly; code that assumed token-granular (page_size=1) allocation later run with a paged host config.","solutions":["Round the request up to a page multiple: need = ((n + page_size - 1) // page_size) * page_size","Verify the pool was configured with the page_size you expect before allocating","Check available_size() after rounding, since rounding up may exceed free slots"],"exampleFix":"# before\nidx = pool.alloc(len(req.input_ids))\n\n# after\nps = pool.page_size\nneed = ((len(req.input_ids) + ps - 1) // ps) * ps\nidx = pool.alloc(need)","handlingStrategy":"validation","validationCode":"need = ((need_size + pool.page_size - 1) // pool.page_size) * pool.page_size\nassert need % pool.page_size == 0","typeGuard":"null","tryCatchPattern":"try:\n    out = pool.alloc(need_size)\nexcept ValueError:\n    out = pool.alloc(round_up(need_size, pool.page_size))","preventionTips":["Centralize a round_up-to-page helper and use it for every alloc call","Check available_size() after rounding up","Unit-test alloc paths with page_size > 1"],"tags":["sglang","memory-pool","allocation","page-alignment"],"backgroundTag":"page-alignment-validation","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}