Repository navigation
[Security] Reject unresolved multimodal inputs before execution - #62152
jperezdealgaba wants to merge 2 commits into
Conversation
|
@WoosukKwon @njhill @robertgshaw2-redhat would you mind reviewing the fix for it? |
hickeyma
left a comment
There was a problem hiding this comment.
Thanks @jperezdealgaba for picking this up. The guard covers the basic case but I don't think it closes the issue yet.
The cache hit paths (prefix cache, encoder cache, EC connector) still let a data=None item reach the worker. On M-RoPE models like Qwen2-VL, the worker reads mm_feature.data in add_request whatever the cache state is. Those paths therefore still take the engine down. Inline comments have the details.
The client also still gets a 500. I'd rather this come back as a 4xx or reuse the retryable multimodal_cache_miss error.
|
Documentation preview: https://vllm--62152.org.readthedocs.build/en/62152/ |
hickeyma
left a comment
There was a problem hiding this comment.
LGTM, thanks @jperezdealgaba
| request.mm_features | ||
| ) | ||
|
|
||
| if request.mm_features: |
There was a problem hiding this comment.
Could you explain why the previous if branch is not sufficient via code comment?
|
This pull request has merge conflicts that must be resolved before it can be |
Co-authored-by: OpenAI Codex <noreply@openai.com> Signed-off-by: Juan Pérez de Algaba <jperezde@redhat.com>
Co-authored-by: OpenAI Codex <noreply@openai.com> Signed-off-by: Juan Pérez de Algaba <jperezde@redhat.com> Co-authored-by: OpenAI Codex
ed1f088 to
975b1f9
Compare
|
This pull request has merge conflicts that must be resolved before it can be |
hickeyma
left a comment
There was a problem hiding this comment.
Thanks @jperezdealgaba. A few things before this can merge:
- Please answer @DarkLight1337's question on
core.py. The receiver cache only exists on the engine for LRU, so a one line comment saying that should do it. test_admission_requires_resolved_multimodal_datacan be shortened. The check never reads scheduler or cache state which means one rejected case and one receiver hit cover it.tests/v1/engine/test_engine_core.pylooks like a better home also.- The
mm_payloadfield descriptions in the chat, completion, responses and anthropicprotocol.pyfiles still say a nullkwargs_datameans every item is cached.
One question on EC prefill. LLaVA renders mm_metadata: null and as far as I can tell the documented prefill flow in renderer.md (drop kwargs_data, send ec_transfer_params) now gets a 400 on models like that. Is that intended? If it is, can you document it? If not, could reject only when uses_mrope is set.
Overview
Reject unresolved multimodal features before worker admission, including when
prefix, encoder, or external encoder caches are warm. Layout-only requests to
/inference/v1/generatereturn HTTP 400 before submission to the engine.Claims
EngineCore.preprocess_add_request, afterreceiver-cache lookup; unresolved items raise
MultiModalCacheMissError.including streaming requests. Render with
mm_payload: "tensors"to includethe payload.
Validation
VLLM_TARGET_DEVICE=cpu PYTHONPATH=. HF_HUB_OFFLINE=1 .venv/bin/python -m pytest tests/v1/core/test_scheduler.py tests/entrypoints/scale_out/token_in_token_out/test_generate_stream.py tests/entrypoints/scale_out/token_in_token_out/test_mm_serde.py -q --tb=short: 307 passed.encoder hit, EC hit, prefix hit, and receiver hit. The Qwen encoder-hit test
fails without the new guard because admission does not raise the typed error.
null payloads, both streaming and non-streaming.
git diff --check: passed.mypy and
/varversus/private/varin the non-root entrypoint wrapper.tests/entrypoints/scale_out/token_in_token_out/test_serving_multimodal_tokens.py::test_layout_only_features_return_bad_request_and_server_recoversto the existing Buildkite entrypoints suite. It verifies layout-only render
output receives HTTP 400 and subsequent rendering with tensors generates
successfully on Qwen3-VL. This test has not been run locally.
are unchanged; the change rejects unresolved inputs.
Details
Encoder outputs and cached prefix tokens do not supply the feature data used
by M-RoPE setup during worker admission. Allowing a null item through on those
cache hits still reaches model assertions. Receiver-cache resolution must run
first, then every unresolved feature must be rejected before scheduling.
The HTTP path now rejects layout-only features before calling the engine.
For direct engine callers, the guard reuses the existing typed cache-miss path.
General generation cache-miss recovery is handled separately in #61656; this
revision does not duplicate its output-processor or endpoint retry changes.
The explicit continuation contract in #60526 is separate from ordinary
multimodal admission. Both related diffs were checked before this revision.
Public
/generatecallers must now supply payload data or the existing ECmetadata contract for each feature. Hashes and placeholder positions alone are
insufficient. Internal receiver-cache references still resolve normally.
AI assistance was used to develop and review this revision. The human submitter
reviewed the changes and approved pushing with GPU end-to-end validation pending.
Pull Request Checklist
/pr-checklistskill.Rebase validation — 2026-10-27
Rebased onto upstream main, preserving the original fix and current surrounding behavior. The duplicate audit found no complete merged or open replacement for this PR’s remaining control.
Preserved upstream scheduler tests. The broad run had 365 passes and four failures; the same four fail on clean upstream because of unavailable model/configuration support in this CPU environment.
Validation on macOS CPU: 365 passed; four unrelated failures also reproduced on clean upstream were excluded from the final run. All applicable changed-file pre-commit checks and
git diff --checkpassed.Native GPU/RDMA execution and model evaluations were not run during this rebase; required CI and human review remain pending. AI assistance (OpenAI Codex) was used for the conflict resolution and validation.