{"record":{"id":"af5cfcff795d16b1","repo":"sgl-project/sglang","slug":"modality-name-must-be-a-list-or-none-got-type","errorCode":null,"errorMessage":"{modality.name} must be a list or None, got {type(data_list)}","messagePattern":"(.+?) must be a list or None, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/multimodal/processors/base_processor.py","lineNumber":1044,"sourceCode":"        for modality, iterator in data_iterators.items():\n            try:\n                next(iterator)\n                logger.warning(\n                    f\"Warning: More {modality.name.lower()} data items provided than corresponding tokens found in the prompt.\"\n                )\n            except StopIteration:\n                pass\n            except Exception:\n                pass\n\n        return futures, task_info\n\n    @staticmethod\n    def _validate_one_modality(modality: Modality, data_list: Optional[list]):\n        if data_list is None:\n            return\n        if not isinstance(data_list, list):\n            raise TypeError(\n                f\"{modality.name} must be a list or None, got {type(data_list)}\"\n            )\n\n        formatted_indices = []\n        for idx, item in enumerate(data_list):\n            if BaseMultimodalProcessor._is_preprocessed_input(item):\n                formatted_indices.append(idx)\n\n        if formatted_indices:\n            if len(data_list) != 1:\n                raise ValueError(\n                    f\"For {modality}, when providing a 'processor_output' or \"\n                    f\"'precomputed_embedding', you must pass exactly one item; \"\n                    f\"received {len(data_list)} items (formatted at indices {formatted_indices}).\"\n                )\n\n    @staticmethod\n    def validate_mm_data(","sourceCodeStart":1026,"sourceCodeEnd":1062,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/multimodal/processors/base_processor.py#L1026-L1062","documentation":"validate_mm_data -> _validate_one_modality enforces that per-modality fields of the mm_data dict (images, audios, videos) are either None or a Python list. Passing a single bare item, tuple, numpy array, or generator raises this TypeError.","triggerScenarios":"Calling the processor with mm_data={'images': single_pil_image} or {'audios': (a1, a2)} (tuple) or a numpy array instead of a list.","commonSituations":"Single-image convenience expectations carried over from other APIs; JSON-decoded tuples; forgetting to wrap the result of a generator/filter in list().","solutions":["Wrap single items in a list: {'images': [img]}","Convert tuples/arrays: list(items)","Leave the field as None when the modality is absent"],"exampleFix":"// before\nmm_data = {'images': pil_img, 'audios': (a1, a2)}\n// after\nmm_data = {'images': [pil_img], 'audios': [a1, a2]}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"def valid_mm_field(v):\n    return v is None or (isinstance(v, list) and all(not isinstance(x, (tuple, set)) for x in v))","tryCatchPattern":null,"preventionTips":["Always wrap media in lists, even single items","Normalize JSON payloads: convert tuples/arrays to list before calling"],"tags":["multimodal","type-validation","input-validation"],"backgroundTag":"wrong-argument-type","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}