Skip to content

fix(vllm): resolve ModuleNotFoundError on vLLM >= 0.14.0 [MLOS-854] - #19789

Open
heyitsgrace996 wants to merge 4 commits into
mainfrom
grace/mlos-854-vllm-input-processor-rename
Open

fix(vllm): resolve ModuleNotFoundError on vLLM >= 0.14.0 [MLOS-854]#19789
heyitsgrace996 wants to merge 4 commits into
mainfrom
grace/mlos-854-vllm-input-processor-rename

Conversation

@heyitsgrace996

@heyitsgrace996 heyitsgrace996 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Description

vLLM 0.14.0 removed vllm.v1.engine.processor (a deprecated compatibility shim in 0.13.0) and moved Processor to vllm.v1.engine.input_processor.InputProcessor. patch()/unpatch() hard-coded the old module path, so the vLLM integration raised ModuleNotFoundError on vLLM >= 0.14.0, silently disabling all vLLM tracing and metrics.

vLLM Change Ref: https://github.com/vllm-project/vllm/blob/v0.13.0/vllm/v1/engine/processor.py

Changes

Fix:

  • patch.py: added _resolve_processor_target() to resolve the moved module/class dynamically instead of hard-coding the old path
  • conftest.py: added a no_gpu marker so GPU-free tests can opt out of require_gpu, plus a fixture-ordering fix so GPU-dependent tests still skip cleanly

Test infra:

  • riotfile.py: split the vllm venv into a floor-pinned + latest-tracked sub-venv, so CI stops being frozen on vllm==0.13.0 and stays current going forward
  • lockfiles: regenerated the 8 affected vLLM lockfiles (4 old ones removed, 8 new ones added for floor + latest across Python 3.10–3.13)
  • registry.yaml / supported_versions.json: regenerated via script to reflect the real tested range (0.10.2–0.27.1)

Testing

  • New unit tests in test_vllm_patch.py: resolver picks an importable module, and patch()/unpatch() correctly wrap/unwrap process_inputs on whichever processor class the installed vLLM exposes.
  • Live repro: real published (pre-fix) ddtrace + stub vLLM modules mirroring the actual 0.13.0/0.14.0 layouts reproduces the crash on 0.14.0; swapping in the fix resolves it on both versions.
  • Full tests/contrib/vllm run completes successfully, validated locally in Docker against real vLLM 0.10.2 and 0.27.1 across Python 3.10-3.12

Risks

Low. Only changes module resolution at patch time; no change to what gets traced.

Additional Notes

Supersedes community PRs #18397, #18512, #18521 (stale + closed, never merged) — fix independently reimplemented and verified against real vLLM source.

Fixes #18393. Fixes MLOS-854.

vLLM 0.14.0 removed the deprecated `vllm.v1.engine.processor` shim and
moved `Processor` to `vllm.v1.engine.input_processor.InputProcessor`.
patch()/unpatch() hard-coded the old module path, so the whole vLLM
integration silently failed to instrument on vLLM >= 0.14.0, dropping
all engine-level spans and metrics (TTFT, queue, prefill, decode,
token counts).

Add a _resolve_processor_target() helper that probes for the new
module first and falls back to the legacy one, used symmetrically in
both patch() and unpatch(). Also add a `no_gpu` pytest marker so the
new resolver regression test can run without a GPU, without changing
skip behavior for any existing model-loading test.
@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codeowners resolved as

Resolved from the full PR diff against main using the target branch CODEOWNERS file.
CODEOWNERS team requests not listed below are not required by the current file set.

.riot/requirements/15798b5.txt                                          @DataDog/apm-python
.riot/requirements/1689461.txt                                          @DataDog/apm-python
.riot/requirements/2043c14.txt                                          @DataDog/apm-python
.riot/requirements/30620e3.txt                                          @DataDog/apm-python
.riot/requirements/39c87f2.txt                                          @DataDog/apm-python
.riot/requirements/460aab7.txt                                          @DataDog/apm-python
.riot/requirements/494e77a.txt                                          @DataDog/apm-python
.riot/requirements/c31c6df.txt                                          @DataDog/apm-python
ddtrace/contrib/internal/vllm/_constants.py                             @DataDog/ml-observability
ddtrace/contrib/internal/vllm/patch.py                                  @DataDog/ml-observability
releasenotes/notes/fix-vllm-input-processor-rename-52bdcf083d5d4036.yaml  @DataDog/apm-python
riotfile.py                                                             @DataDog/apm-python
scripts/integration_registry/registry.yaml                              @DataDog/apm-idm-python
supported_versions.json                                                 @DataDog/apm-core-python @DataDog/apm-idm-python
tests/contrib/vllm/conftest.py                                          @DataDog/ml-observability
tests/contrib/vllm/test_vllm_patch.py                                   @DataDog/ml-observability

@cit-pr-commenter-54b7da

Copy link
Copy Markdown

Circular import analysis

⚠️ Existing circular imports

There are 3 circular imports that already exist on the base branch and have not been changed by this PR.

ddtrace.llmobs -> ddtrace.llmobs._evaluators -> ddtrace.llmobs._evaluators.format -> ddtrace.llmobs._experiment -> ddtrace.llmobs
ddtrace.errortracking._handled_exceptions.bytecode_injector -> ddtrace.errortracking._handled_exceptions.callbacks -> ddtrace.errortracking._handled_exceptions.collector -> ddtrace.errortracking._handled_exceptions.bytecode_reporting -> ddtrace.errortracking._handled_exceptions.bytecode_injector
ddtrace.appsec._asm_request_context -> ddtrace.appsec._iast._iast_request_context_base -> ddtrace.appsec._iast._iast_env -> ddtrace.appsec._iast.reporter -> ddtrace.appsec._exploit_prevention.stack_traces -> ddtrace.appsec._asm_request_context

@cit-pr-commenter-54b7da

cit-pr-commenter-54b7da Bot commented Aug 20, 2026

Copy link
Copy Markdown

Dependency direction analysis

⚠️ Existing dependency direction violations

There are 252 dependency direction violations that already exist on the base branch and have not been changed by this PR.

Show existing violations (showing 5 of 252 highest severity)
ddtrace.internal.tracemethods -×-> ddtrace.trace  (internal-core -> product:tracing, score=135)
ddtrace.internal.opentelemetry.trace -×-> ddtrace.trace  (product:opentelemetry -> product:tracing, score=133)
ddtrace.internal.ci_visibility.git_client -×-> ddtrace.trace  (product:ci_visibility -> product:tracing, score=133)
ddtrace.llmobs._integrations.anthropic -×-> ddtrace.trace  (product:llmobs -> product:tracing, score=133)
ddtrace.internal.ci_visibility.recorder -×-> ddtrace.trace  (product:ci_visibility -> product:tracing, score=133)

To see all violations, download the layers-base.json and layers-pr.json artifacts from this CI job and run:

uv run --script scripts/import-analysis/layers.py compare layers-base.json layers-pr.json

@heyitsgrace996
heyitsgrace996 marked this pull request as ready for review August 20, 2026 13:12
@heyitsgrace996
heyitsgrace996 requested review from a team as code owners August 20, 2026 13:12
@heyitsgrace996
heyitsgrace996 requested a review from ncybul August 20, 2026 13:12
@heyitsgrace996 heyitsgrace996 changed the title fix(vllm): resolve ModuleNotFoundError on vLLM >= 0.14.0 fix(vllm): resolve ModuleNotFoundError on vLLM >= 0.14.0 [MLOS-854] Aug 20, 2026
Comment on lines +4 to +7
vllm: Fixes an issue where the integration failed to instrument vLLM with
``ModuleNotFoundError: No module named 'vllm.v1.engine.processor'`` when
using vLLM versions that renamed this module, silently disabling all
vLLM tracing and metrics.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we maybe include the version of vLLM where the module was renamed so that users can more easily identify whether this fix is relevant to them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed - updated to include version in dbaa6bf

def test_resolve_processor_target_module_importable():
"""The resolved processor module must actually import on the installed vLLM version.

vLLM >= 0.14.0 removed vllm.v1.engine.processor and moved Processor to

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we test vLLM >= 0.14.0? I wonder if we should update the riotfile with an explicit version >= 0.14.0 here: https://github.com/DataDog/dd-trace-py/blob/main/riotfile.py#L3662-L3670

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh really good point, we do not! The lockfiles were actually stuck on 0.13.0, so we were never testing any version with the error.

I updated the riotfile to run two separate venvs, one for the min supported version (0.10.2), and one for latest as we do for the anthropic integration, so it should now auto-update the version in the lockfiles and we won't need to manually pin anything - see commit c53808f.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello ! About that, I'm working on a refactor of supported_versions.json. It will now use a function that every integration was implementing except vllm.

I added a change in #19810 in VLLM that you can add directly to that PR if you prefer. Similar to what I did in my PR, you can merge the two riotfile venvs that you have in your riotfile.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @dubloom! Updated the riotfile. Much simpler :) 633e60a


if found:
return PROCESSOR_MODULE_NEW, f"{PROCESSOR_CLASS_NEW}.{PROCESSOR_METHOD}"
return PROCESSOR_MODULE_OLD, f"{PROCESSOR_CLASS_OLD}.{PROCESSOR_METHOD}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of defaulting to old, I wonder if we should check if this path is indeed importable before patching to avoid the same silent bug as before. We could also include a debug log here, so if the module moves again then we have a signal.

@heyitsgrace996 heyitsgrace996 Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense - updated so now we try to import the module and check the class exists (since vLLM renamed both), and log a debug with a missing module/class and vLLM version in use so it should be easy to figure out if/when the module has been moved again. dbaa6bf

The vllm riot venv pinned a literal ">=0.10.2" range instead of using
riot's `latest` sentinel, which excludes it from the nightly automated
lockfile-bump workflow (generate-package-versions.yml only updates
packages tagged `latest`). That's how vLLM 0.14.0's breaking rename
went unnoticed for months until a customer hit it (MLOS-854) -- CI was
only ever validating against a frozen 0.13.0.

Split the vllm venv into two sub-venvs per the documented pattern in
docs/contributing-testing.rst ("How do I add a new test suite?"),
matching how anthropic/openai already do this: one pinned to the
declared floor (~=0.10.2), one tracking `latest` so the nightly bot
keeps it current going forward.

Regenerated the 8 affected lockfiles and ran the documented
supported-versions/registry update scripts, which now correctly show
vllm tested from 0.10.2 through 0.27.1 (today's latest) instead of a
single frozen 0.13.0.
- Release note now names vLLM >= 0.14.0 explicitly so users can tell
  whether the fix applies to them.
- _resolve_processor_target() now validates that the expected class
  actually exists in each candidate module (not just that the module
  imports), and logs a debug message with the installed vLLM version
  if neither location resolves, instead of silently defaulting to the
  legacy target with no signal.
- Narrowed the fallback's exception handling to ModuleNotFoundError
  keyed on the missing module's own name, so a real import failure
  inside an existing candidate module propagates instead of being
  misdiagnosed as "try the other vLLM version".
@heyitsgrace996
heyitsgrace996 requested review from a team as code owners August 21, 2026 13:52
@datadog-datadog-prod-us1-2

datadog-datadog-prod-us1-2 Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Tests

🎉 All green!

🧪 All tests passed
❄️ No new flaky tests detected

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 633e60a | Docs | View more details | Give us feedback!

@pr-commenter

pr-commenter Bot commented Aug 21, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-08-21 15:36:46

Comparing candidate commit 633e60a in PR branch grace/mlos-854-vllm-input-processor-rename with baseline commit e155a58 in branch main.

📊 Benchmarking dashboard

Found 0 performance improvements and 7 performance regressions! Performance is the same for 615 metrics, 10 unstable metrics.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

scenario:httppropagationextract-wsgi_valid_headers_all

  • 🟥 execution_time [+463.554ns; +527.059ns] or [+8.446%; +9.603%]

scenario:httppropagationinject-ids_only

  • 🟥 execution_time [+1.391µs; +1.498µs] or [+7.165%; +7.715%]

scenario:iastaspectsospath-ospathbasename_aspect

  • 🟥 execution_time [+105.852µs; +115.824µs] or [+25.191%; +27.564%]

scenario:iastaspectssplit-rsplit_aspect

  • 🟥 execution_time [+19.663µs; +22.702µs] or [+13.742%; +15.866%]

scenario:span-start

  • 🟥 execution_time [+1.404ms; +1.591ms] or [+9.420%; +10.675%]

scenario:telemetryaddmetric-1-count-metric-1-times

  • 🟥 execution_time [+492.696ns; +537.078ns] or [+18.396%; +20.053%]

scenario:tracer-small

  • 🟥 execution_time [+30.408µs; +32.444µs] or [+9.120%; +9.730%]

Unstable benchmarks

These benchmarks have a confidence interval too wide to call a change; treat them as noise rather than signal.

scenario:coreapiscenario-context_with_data_listeners

  • unstable execution_time [-671.292ns; +803.927ns] or [-6.109%; +7.316%]

scenario:coreapiscenario-core_dispatch_1_listener

  • unstable execution_time [-32.826ns; +33.868ns] or [-5.406%; +5.578%]

scenario:coreapiscenario-core_dispatch_50_listeners

  • unstable execution_time [-1679.468ns; +1657.179ns] or [-9.874%; +9.742%]

scenario:coreapiscenario-core_dispatch_exception_listeners

  • unstable execution_time [-1173.929ns; +1299.126ns] or [-9.012%; +9.973%]

scenario:coreapiscenario-core_dispatch_listeners

  • unstable execution_time [-345.490ns; +320.038ns] or [-9.348%; +8.659%]

scenario:coreapiscenario-core_dispatch_no_args_listeners

  • unstable execution_time [-269.624ns; +244.057ns] or [-9.198%; +8.326%]

scenario:coreapiscenario-core_dispatch_with_results_1_listener

  • unstable execution_time [-64.244ns; +79.430ns] or [-5.643%; +6.976%]

scenario:coreapiscenario-core_dispatch_with_results_50_listeners

  • unstable execution_time [-4250.364ns; +3716.419ns] or [-10.422%; +9.113%]

scenario:coreapiscenario-core_dispatch_with_results_listeners

  • unstable execution_time [-771.669ns; +775.302ns] or [-9.515%; +9.560%]

scenario:packagesupdateimporteddependencies-import_many_stdlib_cached

  • unstable execution_time [-59.915µs; +62.166µs] or [-9.325%; +9.675%]

@heyitsgrace996
heyitsgrace996 requested a review from ncybul August 21, 2026 14:26
Per review feedback: the floor/latest split doesn't need a second
package to correlate against (unlike anthropic's httpx pairing), so
the nested venvs=[...] from the prior commit was more verbose than
necessary. Collapsed to "vllm": ["~=0.10.2", latest] in the flat pkgs
dict, matching the simpler list-value pattern openai already uses.

Same 8 riot hashes as before, so no lockfile/registry changes needed.
Re-verified all 6 buildable venvs (py3.10-3.12 x floor/latest) still
pass cleanly.
@heyitsgrace996
heyitsgrace996 requested a review from dubloom August 21, 2026 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: vLLM integration broken on vLLM >= 0.14.0, ModuleNotFoundError: No module named 'vllm.v1.engine.processor'

3 participants