{"record":{"id":"50c64c795b2ff16c","repo":"sgl-project/sglang","slug":"every-extra-key-should-be-a-string","errorCode":null,"errorMessage":"Every extra_key should be a string.","messagePattern":"Every extra_key should be a string\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/managers/io_struct.py","lineNumber":793,"sourceCode":"        elif self.parallel_sample_num > 1:\n            raise ValueError(\n                \"Cannot use list custom_logit_processor with parallel_sample_num > 1\"\n            )\n\n    def _normalize_extra_key(self, num):\n        \"\"\"Normalize extra_key for batch processing.\"\"\"\n        if self.extra_key is None:\n            return\n        if isinstance(self.extra_key, str):\n            value = self.extra_key or None\n            self.extra_key = [value] * num\n        elif isinstance(self.extra_key, list):\n            if len(self.extra_key) != self.batch_size:\n                raise ValueError(\n                    \"The length of extra_key should be equal to the batch size.\"\n                )\n            if any(not isinstance(value, str) for value in self.extra_key):\n                raise ValueError(\"Every extra_key should be a string.\")\n            self.extra_key = [value or None for value in self.extra_key]\n            self.extra_key = self.extra_key * self.parallel_sample_num\n        else:\n            raise ValueError(\"extra_key should be a list or a string.\")\n\n    def _normalize_cache_salt(self, num):\n        \"\"\"Normalize cache_salt for batch processing.\"\"\"\n        if self.cache_salt is None:\n            return\n        if isinstance(self.cache_salt, str):\n            value = self.cache_salt or None\n            self.cache_salt = [value] * num\n        elif isinstance(self.cache_salt, list):\n            if len(self.cache_salt) != self.batch_size:\n                raise ValueError(\n                    \"The length of cache_salt should be equal to the batch size.\"\n                )\n            if any(not isinstance(value, str) for value in self.cache_salt):","sourceCodeStart":775,"sourceCodeEnd":811,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/managers/io_struct.py#L775-L811","documentation":"Raised when normalizing batched GenerateReqInput where extra_key is a list but at least one element is not a str. extra_key is the radix-cache attention identity key, and SGLang requires each per-request key to be a string (empty strings are treated as None, i.e. no key).","triggerScenarios":"Calling the generate/batch API with extra_key=[123, 'abc'] or [None, 'k'] where batch_size=2; passing numpy/python objects instead of str.","commonSituations":"Building extra_key from hashes or ints (e.g. md5 digest as bytes, or numeric IDs) instead of str; mixing None into the list.","solutions":["Convert every element to str: extra_key=[str(k) for k in keys]","Use empty string '' (becomes None) for requests that need no cache key","Pass extra_key as a single str to apply to the whole batch"],"exampleFix":"// before\nreq = GenerateReqInput(text=['a','b'], extra_key=[1234, 5678])\n// after\nreq = GenerateReqInput(text=['a','b'], extra_key=['1234','5678'])","handlingStrategy":"validation","validationCode":"assert isinstance(extra_key, list) and len(extra_key) == batch_size\nassert all(isinstance(k, str) for k in extra_key)","typeGuard":"def is_valid_extra_key(k, n) -> bool:\n    return isinstance(k, str) or (isinstance(k, list) and len(k) == n and all(isinstance(x, str) for x in k))","tryCatchPattern":null,"preventionTips":["Always build extra_key as list[str] with len == batch_size","Hash to hex strings, never bytes or ints"],"tags":["sglang","extra-key","cache-key","input-validation","batching"],"backgroundTag":"request-input-validation-failed","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}