From 73bd7c83c4847cd38cb0054dbd9aa912e0eafd03 Mon Sep 17 00:00:00 2001 From: adisivaprasad Date: Wed, 26 Aug 2026 02:10:54 -0700 Subject: [PATCH] [Bugfix][Processor] Replace bare asserts with ValueError in DeepseekVLV2/OCR processors (#53854) Signed-off-by: adisivaprasad Co-authored-by: adisivaprasad --- .../processing/test_deepseek_ocr.py | 24 +++++++++++++++++++ .../processors/deepseek_ocr.py | 13 ++++++---- .../processors/deepseek_vl2.py | 13 ++++++---- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/tests/models/multimodal/processing/test_deepseek_ocr.py b/tests/models/multimodal/processing/test_deepseek_ocr.py index 7bdfbc0832..860f15ef38 100644 --- a/tests/models/multimodal/processing/test_deepseek_ocr.py +++ b/tests/models/multimodal/processing/test_deepseek_ocr.py @@ -132,3 +132,27 @@ class TestDeepseekOCREmptyImagesCrop: "image_size": 1024, # Wrong! Tensor has 640 }, ) + + +class TestDeepseekOCRInputValidation: + """Bare ``assert`` used to validate user input here returned HTTP 500 + (AssertionError) instead of HTTP 400 (ValueError) and disappeared under + ``python -O``, silently corrupting the tokenized sequence. See #53850. + """ + + def test_mismatched_image_count_raises_value_error(self, processor): + """Two ```` tokens with one image must raise ValueError, not + AssertionError (which would yield HTTP 500 and, under ``-O``, silently + drop the middle text segment).""" + image = Image.new("RGB", (100, 100), color="red") + with pytest.raises(ValueError, match="does not match number of images"): + processor(prompt=" and ", images=[image]) + + def test_missing_prompt_raises_value_error(self, processor): + image = Image.new("RGB", (100, 100), color="red") + with pytest.raises(ValueError, match="prompt and images"): + processor(prompt=None, images=[image]) + + def test_missing_images_raises_value_error(self, processor): + with pytest.raises(ValueError, match="prompt and images"): + processor(prompt="\nDescribe this image.", images=None) diff --git a/vllm/transformers_utils/processors/deepseek_ocr.py b/vllm/transformers_utils/processors/deepseek_ocr.py index 618070b506..8a9e36448d 100644 --- a/vllm/transformers_utils/processors/deepseek_ocr.py +++ b/vllm/transformers_utils/processors/deepseek_ocr.py @@ -250,9 +250,8 @@ class DeepseekOCRProcessor(ProcessorMixin): - num_image_tokens (List[int]): the number of image tokens """ - assert prompt is not None and images is not None, ( - "prompt and images must be used at the same time." - ) + if prompt is None or images is None: + raise ValueError("prompt and images must be used at the same time.") sft_format = prompt @@ -311,7 +310,13 @@ class DeepseekOCRProcessor(ProcessorMixin): ): """Tokenize text with tags.""" - assert conversation.count(self.image_token) == len(images) + num_image_tags = conversation.count(self.image_token) + if num_image_tags != len(images): + raise ValueError( + f"Number of {self.image_token!r} tokens in prompt " + f"({num_image_tags}) does not match number of images " + f"({len(images)})." + ) text_splits = conversation.split(self.image_token) images_list, images_crop_list, images_seq_mask, images_spatial_crop = ( [], diff --git a/vllm/transformers_utils/processors/deepseek_vl2.py b/vllm/transformers_utils/processors/deepseek_vl2.py index 5a3c986c13..be6d9800a9 100644 --- a/vllm/transformers_utils/processors/deepseek_vl2.py +++ b/vllm/transformers_utils/processors/deepseek_vl2.py @@ -203,9 +203,8 @@ class DeepseekVLV2Processor(ProcessorMixin): - num_image_tokens (list[int]): the number of image tokens """ - assert prompt is not None and images is not None, ( - "prompt and images must be used at the same time." - ) + if prompt is None or images is None: + raise ValueError("prompt and images must be used at the same time.") sft_format = prompt ( @@ -310,7 +309,13 @@ class DeepseekVLV2Processor(ProcessorMixin): cropping: bool = True, ): """Tokenize text with tags.""" - assert conversation.count(self.image_token) == len(images) + num_image_tags = conversation.count(self.image_token) + if num_image_tags != len(images): + raise ValueError( + f"Number of {self.image_token!r} tokens in prompt " + f"({num_image_tags}) does not match number of images " + f"({len(images)})." + ) text_splits = conversation.split(self.image_token) images_list, images_seq_mask, images_spatial_crop = [], [], [] num_image_tokens = []