diff --git a/tests/test_request_input_bounds.py b/tests/test_request_input_bounds.py index ecab38c922..395abe50c6 100644 --- a/tests/test_request_input_bounds.py +++ b/tests/test_request_input_bounds.py @@ -271,3 +271,19 @@ def test_encode_messages_preserves_small_chat_prompt(encoding_module): "<|begin▁of▁sentence|><|User|>Hello<|Assistant|>" "Hi<|end▁of▁sentence|>Again<|end▁of▁sentence|>" ) + + +@pytest.mark.parametrize( + "encoding_module", + ENCODING_MODULES, + ids=["deepseek_v32", "deepseek_v4"], +) +def test_encode_messages_unknown_role_raises_value_error(encoding_module): + # An invalid role (e.g. uppercase "SYSTEM") is a client error and must be + # raised as ValueError so the OpenAI serving layer maps it to HTTP 400 + # instead of NotImplementedError, which would map to HTTP 501. + with pytest.raises(ValueError, match="Invalid role: SYSTEM"): + encoding_module.encode_messages( + [{"role": "SYSTEM", "content": "Hello"}], + thinking_mode="chat", + ) diff --git a/tests/tokenizers_/test_deepseek_v4.py b/tests/tokenizers_/test_deepseek_v4.py index ea6b30fb70..fd1ba94054 100644 --- a/tests/tokenizers_/test_deepseek_v4.py +++ b/tests/tokenizers_/test_deepseek_v4.py @@ -113,6 +113,17 @@ def test_deepseek_v4_explicitly_disables_thinking(kwargs): assert prompt == ("<|begin▁of▁sentence|><|User|>Hello<|Assistant|>") +def test_deepseek_v4_unknown_role_raises_value_error(): + # Invalid roles are client errors: they must surface as ValueError + # (mapped to HTTP 400 by the OpenAI serving layer), not + # NotImplementedError (mapped to HTTP 501). + with pytest.raises(ValueError, match="Invalid role: SYSTEM"): + _tokenizer().apply_chat_template( + [{"role": "SYSTEM", "content": "Hello"}], + tokenize=False, + ) + + def test_deepseek_v4_uses_v4_tool_prompt_from_request_tools(): tools = [ { diff --git a/vllm/tokenizers/deepseek_v32_encoding.py b/vllm/tokenizers/deepseek_v32_encoding.py index dfe4e478f0..75e8488806 100644 --- a/vllm/tokenizers/deepseek_v32_encoding.py +++ b/vllm/tokenizers/deepseek_v32_encoding.py @@ -258,7 +258,7 @@ def render_message( tool_calls=tool_calls_content, ) else: - raise NotImplementedError(f"Unknown role: {role}") + raise ValueError(f"Invalid role: {role}") return prompt diff --git a/vllm/tokenizers/deepseek_v4_encoding.py b/vllm/tokenizers/deepseek_v4_encoding.py index 461f7f391d..ceb702d3a0 100644 --- a/vllm/tokenizers/deepseek_v4_encoding.py +++ b/vllm/tokenizers/deepseek_v4_encoding.py @@ -353,7 +353,7 @@ def render_message( tool_calls=tc_content, ) else: - raise NotImplementedError(f"Unknown role: {role}") + raise ValueError(f"Invalid role: {role}") # Append transition tokens based on what follows if index + 1 < len(messages) and messages[index + 1].get("role") not in ["assistant", "latest_reminder"]: