{"record":{"id":"4160de144da7247b","repo":"sgl-project/sglang","slug":"component-attention-backend-key-must-be-a-string","errorCode":null,"errorMessage":"Component attention backend key must be a string","messagePattern":"Component attention backend key must be a string","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/multimodal_gen/runtime/server_args/server_args.py","lineNumber":1135,"sourceCode":"            if not pair:\n                continue\n            if \"=\" not in pair:\n                raise ValueError(\n                    \"component_attention_backends must use component=backend entries\"\n                )\n            component, backend = pair.split(\"=\", 1)\n            result[component.strip()] = backend.strip()\n        return result\n\n    @classmethod\n    def _normalize_component_attention_backends(\n        cls, value: dict[str, str] | str | None\n    ) -> dict[str, str]:\n        raw = cls._parse_component_attention_backend_map(value)\n        normalized: dict[str, str] = {}\n        for component, backend in raw.items():\n            if not isinstance(component, str):\n                raise ValueError(\"Component attention backend key must be a string\")\n            component_name = component.strip().replace(\"-\", \"_\")\n            if not component_name:\n                raise ValueError(\"Component attention backend key must not be empty\")\n            normalized[component_name] = cls._normalize_attention_backend_name(backend)\n        return normalized\n\n    def resolve_component_attention_backend(\n        self, *component_names: str | None\n    ) -> tuple[AttentionBackendEnum | None, str | None]:\n        for component_name in component_names:\n            if component_name is None:\n                continue\n            key = component_name.replace(\"-\", \"_\")\n            fallback_keys = [key]\n            if key.endswith(\"_2\"):\n                # Secondary two-stage components inherit the base component\n                # backend unless explicitly overridden.\n                fallback_keys.append(key[:-2])","sourceCodeStart":1117,"sourceCodeEnd":1153,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/multimodal_gen/runtime/server_args/server_args.py#L1117-L1153","documentation":"After parsing, each key of the component-attention-backend map must be a Python str. This only fires for programmatic dict input (or JSON) whose keys are non-strings (e.g. ints from a YAML config where 42 was used as a component key), since CLI string parsing always yields str keys.","triggerScenarios":"ServerArgs(component_attention_backends={42: 'flash'}) or JSON '{\"42\": ...}' parsed to non-str keys via a permissive loader.","commonSituations":"Loading config from YAML/JSON where numeric-looking keys were auto-converted; constructing the dict from another mapping with non-str keys.","solutions":["Convert keys to strings: {str(k): v for k, v in cfg.items()}","Quote keys in the JSON/YAML source","Fix the config loader to preserve string keys"],"exampleFix":"# before\nbackends = {int(k): v for k, v in cfg.items()}\n# after\nbackends = {str(k): v for k, v in cfg.items()}","handlingStrategy":"type-guard","validationCode":"backends = {str(k): v for k, v in raw_backends.items()}","typeGuard":"def has_str_keys(d: dict) -> bool:\n    return all(isinstance(k, str) and k.strip() for k in d)","tryCatchPattern":null,"preventionTips":["Normalize config keys to str after loading YAML/JSON"],"tags":["config","type-error","attention-backend"],"backgroundTag":"invalid-argument-type","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}