{"record":{"id":"8b57a68b6b356ec7","repo":"sgl-project/sglang","slug":"unsupported-image-type-type","errorCode":null,"errorMessage":"Unsupported image type: {type}","messagePattern":"Unsupported image type: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/multimodal/processors/step3_vl.py","lineNumber":128,"sourceCode":"\n    def __call__(self, image, is_patch=False):\n        if is_patch:\n            return {\"pixel_values\": self.patch_transform(image).unsqueeze(0)}\n        else:\n            return {\"pixel_values\": self.transform(image).unsqueeze(0)}\n\n\nclass ImagePatcher:\n    def get_image_size(self, img: Step3Image) -> tuple[int, int]:\n        if isinstance(img, Image.Image):\n            return img.size\n        if isinstance(img, torch.Tensor):\n            if img.ndim != 3:\n                raise TypeError(\n                    f\"Expected CHW image tensor, got shape {tuple(img.shape)}\"\n                )\n            return int(img.shape[-1]), int(img.shape[-2])\n        raise TypeError(f\"Unsupported image type: {type(img)}\")\n\n    def determine_window_size(self, long: int, short: int) -> int:\n        if long <= 728:\n            return short if long / short > 1.5 else 0\n        return min(short, 504) if long / short > 4 else 504\n\n    def slide_window(\n        self,\n        width: int,\n        height: int,\n        sizes: list[tuple[int, int]],\n        steps: list[tuple[int, int]],\n        img_rate_thr: float = 0.6,\n    ) -> tuple[list[tuple[int, int, int, int]], tuple[int, int]]:\n        assert 1 >= img_rate_thr >= 0, \"The `img_rate_thr` should lie in 0~1\"\n        windows = []\n        # Sliding windows.\n        for size, step in zip(sizes, steps):","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/multimodal/processors/step3_vl.py#L110-L146","documentation":"ImagePatcher.get_image_size accepts only PIL.Image.Image instances and 3D CHW torch tensors. Anything else — numpy arrays, paths, bytes, tf tensors — reaches the final raise. This is a deliberate strict contract: the patcher needs pixel dimensions and only knows how to extract them from those two types.","triggerScenarios":"Calling ImagePatcher.__call__ or square_pad with a np.ndarray, file path string, raw bytes, or any non-PIL/non-tensor object.","commonSituations":"Passing image paths or numpy frames (common from OpenCV/video pipelines) expecting the processor to do the loading; wrapping images in custom container objects.","solutions":["Convert numpy to PIL: Image.fromarray(cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB))","Load from path: Image.open(path).convert('RGB')","Convert numpy to a CHW float tensor if PIL is unavailable"],"exampleFix":"# before\npatched = patcher(cv2_frame)  # np.ndarray\n# after\nfrom PIL import Image\npatched = patcher(Image.fromarray(cv2.cvtColor(cv2_frame, cv2.COLOR_BGR2RGB)))","handlingStrategy":"type-guard","validationCode":"if isinstance(img, np.ndarray):\n    img = Image.fromarray(img[..., ::-1]) if img.shape[-1] == 3 else Image.fromarray(img)","typeGuard":"def is_supported_image(x) -> bool:\n    import PIL.Image, torch\n    return isinstance(x, (PIL.Image.Image,)) or (isinstance(x, torch.Tensor) and x.ndim == 3)","tryCatchPattern":null,"preventionTips":["Normalize all inputs to PIL or CHW tensors at the API boundary","Never pass file paths or raw bytes to image processors"],"tags":["multimodal","image-processing","type-validation","step3-vl"],"backgroundTag":"unsupported-input-type","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}