{"record":{"id":"d045c65b274c47fb","repo":"sgl-project/sglang","slug":"image-mode-mode-is-not-supported-with-multiple","errorCode":null,"errorMessage":"image_mode='{mode}' is not supported with multiple images (got {num_images} images). Please use one of: {allowed}","messagePattern":"image_mode='(.+?)' is not supported with multiple images \\(got (.+?) images\\)\\. Please use one of: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/multimodal/processors/unlimited_ocr.py","lineNumber":46,"sourceCode":"def _resolve_mode(images_config, num_images: int = 1) -> dict:\n    \"\"\"Return processor kwargs from images_config (or default).\"\"\"\n    mode = _DEFAULT_MODE\n    if images_config:\n        mode = images_config.get(\"image_mode\", _DEFAULT_MODE)\n    key = mode.strip().lower()\n    preset = _IMAGE_MODE_PRESETS.get(key)\n    if preset is None:\n        logger.error(\n            f\"Unknown image_mode '{mode}'. Supported: {', '.join(_IMAGE_MODE_PRESETS)}\"\n        )\n        raise ValueError(\n            f\"Unknown image_mode '{mode}'. \"\n            f\"Supported: {', '.join(_IMAGE_MODE_PRESETS)}\"\n        )\n    _MULTI_IMAGE_ALLOWED = (\"tiny\", \"small\", \"base\")\n    base_size, image_size, crop_mode = preset\n    if num_images > 1 and key not in _MULTI_IMAGE_ALLOWED:\n        raise ValueError(\n            f\"image_mode='{mode}' is not supported with multiple images \"\n            f\"(got {num_images} images). \"\n            f\"Please use one of: {list(_MULTI_IMAGE_ALLOWED)}\"\n        )\n    return dict(zip((\"base_size\", \"image_size\", \"crop_mode\"), preset))\n\n\nclass UnlimitedOCRProcessor(BaseMultimodalProcessor):\n    \"\"\"Multimodal processor for UNLIMITED-OCR model.\"\"\"\n\n    models = [UnlimitedOCRForCausalLM]\n    gpu_image_decode = False\n\n    def __init__(self, hf_config, server_args, _processor, *args, **kwargs):\n        \"\"\"Initialize UnlimitedOCRProcessor.\"\"\"\n        super().__init__(hf_config, server_args, _processor, *args, **kwargs)\n        self.mm_tokens = MultimodalSpecialTokens(\n            image_token=\"<image>\", image_token_id=self._processor.image_token_id","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/multimodal/processors/unlimited_ocr.py#L28-L64","documentation":"Only the lightweight OCR modes ('tiny', 'small', 'base') support multi-image requests. When num_images > 1 and the resolved mode key is not in _MULTI_IMAGE_ALLOWED, the processor raises ValueError telling you to switch modes. This prevents resolution-heavy modes from multiplying crop windows across many images.","triggerScenarios":"Sending a request with 2+ images while image_mode resolves to a multi-image-disallowed preset (any preset outside tiny/small/base).","commonSituations":"Batching document pages with a high-resolution mode; per-image mode overrides not applied so a global heavy mode is used for a multi-page scan request.","solutions":["Switch image_mode to 'tiny', 'small', or 'base' for multi-image requests","Split the request into one image per request to keep the heavy mode","Pre-validate mode vs image count client-side before sending"],"exampleFix":"# before\nimage_mode='hd'; images=[page1, page2]\n# after\nimage_mode='base'; images=[page1, page2]","handlingStrategy":"validation","validationCode":"MULTI_OK = ('tiny', 'small', 'base')\nif len(images) > 1 and image_mode.strip().lower() not in MULTI_OK:\n    image_mode = 'base'  # or reject","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Map request shape to mode policy in the client: multi-image always uses a lightweight mode"],"tags":["multimodal","ocr","multi-image","config-validation"],"backgroundTag":"unsupported-option-combination","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}