[Bugfix][Processor] Replace bare asserts with ValueError in DeepseekVLV2/OCR processors (#53854)

Signed-off-by: adisivaprasad <adisivaprasad@users.noreply.github.com> Co-authored-by: adisivaprasad <adisivaprasad@users.noreply.github.com>

adisivaprasad committed Aug 26, 2026 at 02:10 UTC 73bd7c83c4847cd38cb0054dbd9aa912e0eafd03
3 files changed +42 -8
tests/models/multimodal/processing/test_deepseek_ocr.py
+24
@@ -132,3 +132,27 @@ class TestDeepseekOCREmptyImagesCrop:
132 "image_size": 1024, # Wrong! Tensor has 640
133 },
134 )
135 +
136 +
137 +class TestDeepseekOCRInputValidation:
138 + """Bare ``assert`` used to validate user input here returned HTTP 500
139 + (AssertionError) instead of HTTP 400 (ValueError) and disappeared under
140 + ``python -O``, silently corrupting the tokenized sequence. See #53850.
141 + """
142 +
143 + def test_mismatched_image_count_raises_value_error(self, processor):
144 + """Two ``<image>`` tokens with one image must raise ValueError, not
145 + AssertionError (which would yield HTTP 500 and, under ``-O``, silently
146 + drop the middle text segment)."""
147 + image = Image.new("RGB", (100, 100), color="red")
148 + with pytest.raises(ValueError, match="does not match number of images"):
149 + processor(prompt="<image> and <image>", images=[image])
150 +
151 + def test_missing_prompt_raises_value_error(self, processor):
152 + image = Image.new("RGB", (100, 100), color="red")
153 + with pytest.raises(ValueError, match="prompt and images"):
154 + processor(prompt=None, images=[image])
155 +
156 + def test_missing_images_raises_value_error(self, processor):
157 + with pytest.raises(ValueError, match="prompt and images"):
158 + processor(prompt="<image>\nDescribe this image.", images=None)
vllm/transformers_utils/processors/deepseek_ocr.py
+9 -4
@@ -250,9 +250,8 @@ class DeepseekOCRProcessor(ProcessorMixin):
250 - num_image_tokens (List[int]): the number of image tokens
251 """
252
253 - assert prompt is not None and images is not None, (
254 - "prompt and images must be used at the same time."
255 - )
253 + if prompt is None or images is None:
254 + raise ValueError("prompt and images must be used at the same time.")
255
256 sft_format = prompt
257
@@ -311,7 +310,13 @@ class DeepseekOCRProcessor(ProcessorMixin):
310 ):
311 """Tokenize text with <image> tags."""
312
314 - assert conversation.count(self.image_token) == len(images)
313 + num_image_tags = conversation.count(self.image_token)
314 + if num_image_tags != len(images):
315 + raise ValueError(
316 + f"Number of {self.image_token!r} tokens in prompt "
317 + f"({num_image_tags}) does not match number of images "
318 + f"({len(images)})."
319 + )
320 text_splits = conversation.split(self.image_token)
321 images_list, images_crop_list, images_seq_mask, images_spatial_crop = (
322 [],
vllm/transformers_utils/processors/deepseek_vl2.py
+9 -4
@@ -203,9 +203,8 @@ class DeepseekVLV2Processor(ProcessorMixin):
203 - num_image_tokens (list[int]): the number of image tokens
204 """
205
206 - assert prompt is not None and images is not None, (
207 - "prompt and images must be used at the same time."
208 - )
206 + if prompt is None or images is None:
207 + raise ValueError("prompt and images must be used at the same time.")
208
209 sft_format = prompt
210 (
@@ -310,7 +309,13 @@ class DeepseekVLV2Processor(ProcessorMixin):
309 cropping: bool = True,
310 ):
311 """Tokenize text with <image> tags."""
313 - assert conversation.count(self.image_token) == len(images)
312 + num_image_tags = conversation.count(self.image_token)
313 + if num_image_tags != len(images):
314 + raise ValueError(
315 + f"Number of {self.image_token!r} tokens in prompt "
316 + f"({num_image_tags}) does not match number of images "
317 + f"({len(images)})."
318 + )
319 text_splits = conversation.split(self.image_token)
320 images_list, images_seq_mask, images_spatial_crop = [], [], []
321 num_image_tokens = []