[Bugfix] Return 400 instead of 500 when multimodal data is sent to a text-only model (#48473)

Signed-off-by: Hoang Nguyen Tien <hoang.nguyentien.2601@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

Hoang Nguyen committed Jul 14, 2026 at 15:15 UTC 038ec293b17d8d1018b5494a97187597b10c5182
2 files changed +32 -2
tests/renderers/test_process_multi_modal_uuids.py
+30
@@ -1,11 +1,14 @@
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 +from http import HTTPStatus
5 +
6 import pytest
7
8 from vllm.assets.image import ImageAsset
9 from vllm.assets.video import VideoAsset
10 from vllm.config import CacheConfig, ModelConfig, VllmConfig
11 +from vllm.entrypoints.serve.utils.error_response import create_error_response
12 from vllm.multimodal.parse import parse_mm_uuids
13 from vllm.renderers.hf import HfRenderer
14 from vllm.tokenizers.registry import cached_tokenizer_from_config
@@ -35,6 +38,33 @@ def _build_renderer(
38 )
39
40
41 +def _build_text_only_renderer() -> HfRenderer:
42 + model_config = ModelConfig(model="openai-community/gpt2", max_model_len=128)
43 +
44 + return HfRenderer(
45 + VllmConfig(model_config=model_config),
46 + cached_tokenizer_from_config(model_config),
47 + )
48 +
49 +
50 +def test_text_only_model_mm_data_maps_to_bad_request():
51 + """Sending multimodal data to a text-only model is a client mistake, so it
52 + must surface as a ValueError and reach the client as HTTP 400, not 500."""
53 + renderer = _build_text_only_renderer()
54 +
55 + with pytest.raises(ValueError, match="text-only") as exc_info:
56 + renderer._process_multimodal(
57 + prompt="What is in this image?",
58 + mm_data={"image": [cherry_pil_image]},
59 + mm_uuids=None,
60 + mm_processor_kwargs=None,
61 + tokenization_kwargs=None,
62 + )
63 +
64 + error_response = create_error_response(exc_info.value)
65 + assert error_response.error.code == HTTPStatus.BAD_REQUEST
66 +
67 +
68 def test_multi_modal_uuids_length_mismatch_raises():
69 renderer = _build_renderer()
70
vllm/renderers/base.py
+2 -2
@@ -735,13 +735,13 @@ class BaseRenderer(ABC, Generic[_T]):
735 *,
736 skip_mm_cache: bool = False,
737 ) -> "MultiModalInput":
738 - mm_req_id = f"renderer{self.api_process_rank}-mm-{self._mm_req_counter.inc(1)}"
739 -
738 if skip_mm_cache and self._readonly_mm_processor is not None:
739 mm_processor = self._readonly_mm_processor
740 else:
741 mm_processor = self.get_mm_processor()
742
743 + mm_req_id = f"renderer{self.api_process_rank}-mm-{self._mm_req_counter.inc(1)}"
744 +
745 mm_data_items = mm_processor.info.parse_mm_data(mm_data)
746 mm_uuid_items = parse_mm_uuids(mm_uuids)
747