[Bugfix] Validate extension integers before engine serialization (#55606)

Signed-off-by: khluu <khluu000@gmail.com> Co-authored-by: Codex <noreply@openai.com>

Kevin H. Luu committed Sep 8, 2026 at 01:30 UTC 5db652225f00b55783823ae6606d36925e3e3efe
2 files changed +44
tests/test_sampling_params.py
+22
@@ -49,3 +49,25 @@ def test_diffusion_accepts_top_k_top_p():
49 def test_non_diffusion_models_unaffected():
50 params = SamplingParams(temperature=0.7, top_k=10, seed=42)
51 params.verify(MockModelConfig(), None, None, None)
52 +
53 +
54 +@pytest.mark.parametrize("value", [-(2**63) - 1, 2**64])
55 +def test_extra_args_rejects_nested_integer_overflow(value):
56 + """Reject extension values before they reach the engine transport."""
57 + with pytest.raises(VLLMValidationError, match="extra_args integers"):
58 + SamplingParams(extra_args={"ec_transfer_params": {"nested": [{"x": value}]}})
59 +
60 +
61 +@pytest.mark.parametrize("value", [-(2**63), 2**63 - 1, 2**63, 2**64 - 1, True])
62 +def test_extra_args_accepts_messagepack_integer_boundaries(value):
63 + extra_args = {"kv_transfer_params": {"nested": [{"x": value}]}}
64 + assert SamplingParams(extra_args=extra_args).extra_args == extra_args
65 +
66 +
67 +def test_extra_args_preserves_custom_objects_and_shared_containers():
68 + custom = object()
69 + shared = [custom, (None, "value", 1.5)]
70 + extra_args = {"first": shared, "second": shared}
71 + params = SamplingParams(extra_args=extra_args)
72 + assert params.extra_args["first"][0] is custom
73 + assert params.extra_args["first"] is params.extra_args["second"]
vllm/sampling_params.py
+22
@@ -544,6 +544,8 @@ class SamplingParams(
544
545 def _verify_args(self) -> None:
546 _verify_num_sequences(self.n, "n")
547 + if self.extra_args:
548 + self._verify_extra_args()
549 if not -2.0 <= self.presence_penalty <= 2.0:
550 raise VLLMValidationError(
551 f"presence_penalty must be in [-2, 2], got {self.presence_penalty}."
@@ -655,6 +657,26 @@ class SamplingParams(
657 f"Got bad_words={self.bad_words}"
658 )
659
660 + def _verify_extra_args(self) -> None:
661 + # JSON accepts arbitrary integers, but the engine's MessagePack
662 + # transport only supports signed/unsigned 64-bit integers.
663 + pending: list[Any] = [self.extra_args]
664 + visited: set[int] = set()
665 + while pending:
666 + value = pending.pop()
667 + if isinstance(value, int) and not -(2**63) <= value < 2**64:
668 + raise VLLMValidationError(
669 + "extra_args integers must be between -2**63 and 2**64 - 1.",
670 + parameter="extra_args",
671 + )
672 + if isinstance(value, (dict, list, tuple)) and id(value) not in visited:
673 + visited.add(id(value))
674 + if isinstance(value, dict):
675 + pending.extend(value.keys())
676 + pending.extend(value.values())
677 + else:
678 + pending.extend(value)
679 +
680 def _verify_greedy_sampling(self) -> None:
681 if self.n > 1:
682 raise VLLMValidationError(