{"record":{"id":"efdaf18c43edc7e0","repo":"sgl-project/sglang","slug":"mm-process-config-key-must-be-a-dict-but-got","errorCode":null,"errorMessage":"mm_process_config['{key}'] must be a dict, but got {type(cfg.mm_process_config[key])}","messagePattern":"mm_process_config\\['(.+?)'\\] must be a dict, but got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/server_args.py","lineNumber":4388,"sourceCode":"    def _handle_multimodal(self):\n        \"\"\"Validate mm_process_config structure before model loading.\"\"\"\n        cfg = resolving_view(self)\n        if (\n            cfg.mm_preprocess_cache_size_mb is not None\n            and cfg.mm_preprocess_cache_size_mb < 0\n        ):\n            raise ValueError(\"mm_preprocess_cache_size_mb must be non-negative\")\n        if cfg.mm_process_config is not None:\n            if not isinstance(cfg.mm_process_config, dict):\n                raise TypeError(\n                    f\"mm_process_config must be a dict, \"\n                    f\"but got {type(cfg.mm_process_config)}\"\n                )\n            for key in (\"image\", \"video\", \"audio\"):\n                if key in cfg.mm_process_config and not isinstance(\n                    cfg.mm_process_config[key], dict\n                ):\n                    raise TypeError(\n                        f\"mm_process_config['{key}'] must be a dict, \"\n                        f\"but got {type(cfg.mm_process_config[key])}\"\n                    )\n\n    def _handle_media_url_security(self):\n        \"\"\"Normalize and publish the media URL policy before workers start.\"\"\"\n        cfg = resolving_view(self)\n        self._declare(\n            \"_handle_media_url_security\",\n            allowed_media_domains=configure_media_url_security(\n                cfg.allowed_media_domains,\n                cfg.media_url_max_file_size_mb,\n            ),\n        )\n\n    def _handle_deprecated_args(self):\n        cfg = resolving_view(self)\n        if cfg.disable_fast_image_processor:","sourceCodeStart":4370,"sourceCodeEnd":4406,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/server_args.py#L4370-L4406","documentation":"Within --mm-process-config, only the keys image, video, and audio are inspected, and each must map to a dict of override fields. This TypeError is raised when one of those keys maps to a non-dict value (string, number, list).","triggerScenarios":"Passing --mm-process-config '{\"image\": \"fast\"}' or '{\"video\": [1,2]}' — a valid top-level dict but a non-dict value under image/video/audio.","commonSituations":"Shorthand attempts like {\"image\": 4} meaning 'use 4 threads'; nested JSON quoting broken by the shell; schema drift from older config formats.","solutions":["Wrap per-modality settings in an object: {\"image\": {\"...\": ...}}","Check the model's mm preprocessing docs for accepted keys per modality","Echo the final arg string and run it through python -c 'import json,sys; json.load(open(...))' or json.loads to verify structure"],"exampleFix":"# before\n--mm-process-config '{\"image\": 4}'\n# after\n--mm-process-config '{\"image\": {\"num_threads\": 4}}'","handlingStrategy":"type-guard","validationCode":"import json\ncfg = json.loads(args.mm_process_config)\nfor k in ('image', 'video', 'audio'):\n    if k in cfg:\n        assert isinstance(cfg[k], dict), f'{k} settings must be an object'","typeGuard":"def valid_mm_sections(cfg: dict) -> bool:\n    return all(\n        isinstance(cfg.get(k), dict) for k in ('image', 'video', 'audio') if k in cfg\n    )","tryCatchPattern":null,"preventionTips":["Reference the documented per-modality schema","Validate nested structure in config pipelines"],"tags":["multimodal","json","server-args","type-error"],"backgroundTag":"invalid-json-config","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}