{"record":{"id":"8b0c77c136ac33f2","repo":"sgl-project/sglang","slug":"internvl-qwen-image-data-provided-but-no-images","errorCode":null,"errorMessage":"[internvl][qwen] image_data provided but no images parsed from prompt placeholders","messagePattern":"\\[internvl\\]\\[qwen\\] image_data provided but no images parsed from prompt placeholders","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/multimodal/processors/internvl.py","lineNumber":464,"sourceCode":"        for image in base_output.images:\n            if isinstance(image, Image.Image):\n                img_np = np.array(image.convert(\"RGB\"))\n                tensor = (\n                    torch.from_numpy(img_np).permute(2, 0, 1).to(get_device()).float()\n                    / 255.0\n                )\n            else:\n                tensor = image.to(get_device())\n\n            tensor = (tensor - mean) / std\n            tiles = self.dynamic_preprocess(\n                tensor, image_size=448, max_num=img_max_num, use_thumbnail=True\n            )\n            pixel_values_list.append(tiles)\n            num_patches_list.append(int(tiles.shape[0]))\n\n        if image_data and not pixel_values_list:\n            raise ValueError(\n                \"[internvl][qwen] image_data provided but no images parsed from prompt placeholders\"\n            )\n\n        image_tensor = (\n            torch.cat(pixel_values_list, dim=0) if pixel_values_list else None\n        )\n\n        # ----- Videos -> frame tiles (optional) -----\n        video_tensor = None\n        video_patch_lists = []\n        video_pixel_values = []\n\n        requested_frames = int(\n            kwargs.get(\"video_num_frames\", self.DEFAULT_VIDEO_NUM_FRAMES)\n        )\n        num_frames = self._resolve_video_num_frames(\n            requested=requested_frames,\n            num_videos=len(base_output.videos),","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/multimodal/processors/internvl.py#L446-L482","documentation":"In the Qwen-flavored InternVL path, image_data was provided but the prompt string contained no image placeholders, so no pixel_values were ever parsed and the model would see images it cannot place. The processor scans the prompt for per-image placeholder markers (e.g. <img>...</img> or <image> tokens) and pairs each with an image; zero parsed images plus non-empty image_data triggers this raise.","triggerScenarios":"Calling process_qwen_mm_data_async with image_data=[...] but a prompt string lacking image placeholder markup; placeholders spelled differently than the template the parser expects; chat template not applied so placeholder tokens were never inserted.","commonSituations":"Building prompts manually with plain markdown ![img](...) instead of the model's placeholder syntax; forgetting apply_chat_template; template version drift changing the placeholder string.","solutions":["Apply the InternVL-Qwen chat template / insert one image placeholder per image into the prompt before calling","Match the exact placeholder syntax the processor scans for (see its regex in internvl.py)","If images are optional for this request, don't pass image_data"],"exampleFix":"# before\nprompt = 'Describe this.'  # no placeholder\nout = await proc.process_qwen_mm_data_async(image_data=[img], prompt=prompt)\n# after\nprompt = f'<image>Describe this.'  # one placeholder per image\nout = await proc.process_qwen_mm_data_async(image_data=[img], prompt=prompt)","handlingStrategy":"validation","validationCode":"n_ph = count_image_placeholders(prompt)  # regex used by internvl processor\nif image_data and n_ph == 0:\n    prompt = insert_image_placeholders(prompt, len(image_data))\nif image_data and n_ph != len(image_data):\n    raise UserInputError('placeholder count must equal image count')","typeGuard":"def prompt_has_placeholders(prompt: str, n_images: int) -> bool:\n    return count_image_placeholders(prompt) == n_images","tryCatchPattern":"try:\n    out = await proc.process_qwen_mm_data_async(image_data, prompt)\nexcept ValueError as e:\n    if 'no images parsed' in str(e):\n        prompt = f'<image>'*len(image_data) + prompt\n        out = await proc.process_qwen_mm_data_async(image_data, prompt)\n    else: raise","preventionTips":["Always run prompts through apply_chat_template","Verify placeholder syntax matches the processor's parser regex"],"tags":["multimodal","internvl","qwen","placeholder-mismatch"],"backgroundTag":"placeholder-count-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}