vllm - 💡(How to fix) Fix [Bug]: [V1] `prompt_tokens_details` always `null` in API response despite `--enable-prompt-tokens-details` (14+ months, incomplete fix in PR #18149)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

usage.prompt_tokens_details is always null in the OpenAI-compatible API response on V1 engine, even with --enable-prompt-tokens-details and --enable-prefix-caching enabled.

This was previously reported in #16162 (2025-04) and #18062 (2025-05), and supposedly fixed by PR #18149 (merged 2025-05-23). However, the fix is incomplete — it only wired num_cached_tokens through the scheduler/output processor, but never mapped it to prompt_tokens_details in the OpenAI API serving layer.

This bug has been open for 14+ months and is confirmed still broken on the latest nightly.

Root Cause

PR #18149 modified the engine-internal path:

vllm/v1/core/sched/scheduler.py      ✅ num_cached_tokens populated
vllm/v1/engine/__init__.py            ✅ propagated in EngineCoreOutput
vllm/v1/engine/output_processor.py    ✅ stored in RequestOutput
vllm/v1/request.py                    ✅ field added

But the API server response path was never updated:

[OutputProcessor] num_cached_tokens = N   ✅
[OpenAI Serving Layer → UsageInfo]        ❌ not mapped
[API JSON Response]                       ❌ prompt_tokens_details: null

The OpenAI serving layer (e.g. vllm/entrypoints/openai/serving_chat.py or the UsageInfo builder) does not read num_cached_tokens from RequestOutput and does not populate prompt_tokens_details.cached_tokens.

Fix Action

Fix / Workaround

This was previously reported in #16162 (2025-04) and #18062 (2025-05), and supposedly fixed by PR #18149 (merged 2025-05-23). However, the fix is incomplete — it only wired num_cached_tokens through the scheduler/output processor, but never mapped it to prompt_tokens_details in the OpenAI API serving layer.

Code Example

vllm/v1/core/sched/scheduler.py      ✅ num_cached_tokens populated
vllm/v1/engine/__init__.py            ✅ propagated in EngineCoreOutput
vllm/v1/engine/output_processor.py    ✅ stored in RequestOutput
vllm/v1/request.py                    ✅ field added

---

[OutputProcessor] num_cached_tokens = N[OpenAI Serving LayerUsageInfo]        ❌ not mapped
[API JSON Response]                       ❌ prompt_tokens_details: null

---

vllm serve facebook/opt-125m \
  --enable-prefix-caching \
  --enable-prompt-tokens-details

---

# Run this twice
curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "facebook/opt-125m",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant. Please provide detailed and comprehensive answers to all questions. This is padding to ensure enough tokens for prefix caching to activate on the second request."},
      {"role": "user", "content": "What is the capital of France?"}
    ],
    "max_tokens": 20
  }' | jq '.usage'

---

{
  "prompt_tokens": 48,
  "total_tokens": 68,
  "completion_tokens": 20,
  "prompt_tokens_details": null
}

---

{
  "prompt_tokens": 48,
  "total_tokens": 68,
  "completion_tokens": 20,
  "prompt_tokens_details": {
    "cached_tokens": 32
  }
}

---

vllm:prefix_cache_hits_total > 0

---

# Likely location: vllm/entrypoints/openai/serving_chat.py
# or wherever UsageInfo is constructed from RequestOutput

if self.enable_prompt_tokens_details and request_output.num_cached_tokens is not None:
    usage.prompt_tokens_details = PromptTokensDetails(
        cached_tokens=request_output.num_cached_tokens
    )
RAW_BUFFERClick to expand / collapse

Your current environment

<details> <summary>Environment</summary>
  • vLLM version: v0.22.1rc1.dev166+gd0975a4b5 (V1 engine, default)
  • Launch flags: --enable-prefix-caching --enable-prompt-tokens-details
  • Also confirmed broken on: v0.22.1rc1 nightly (2026-06-01) per forum report
</details>

🐛 Describe the bug

Summary

usage.prompt_tokens_details is always null in the OpenAI-compatible API response on V1 engine, even with --enable-prompt-tokens-details and --enable-prefix-caching enabled.

This was previously reported in #16162 (2025-04) and #18062 (2025-05), and supposedly fixed by PR #18149 (merged 2025-05-23). However, the fix is incomplete — it only wired num_cached_tokens through the scheduler/output processor, but never mapped it to prompt_tokens_details in the OpenAI API serving layer.

This bug has been open for 14+ months and is confirmed still broken on the latest nightly.

Prior reports confirming this bug

ReferenceDateVersionStatus
#161622025-04-07V1 devClosed (marked fixed)
#180622025-05-13V1 masterClosed by PR #18149
PR #181492025-05-23Merged (incomplete fix)
Forum report2026-06-02v0.22.1rc1 nightlyStill broken
#433702026-05-21V1 disaggregatedSeparate but related

Root cause

PR #18149 modified the engine-internal path:

vllm/v1/core/sched/scheduler.py      ✅ num_cached_tokens populated
vllm/v1/engine/__init__.py            ✅ propagated in EngineCoreOutput
vllm/v1/engine/output_processor.py    ✅ stored in RequestOutput
vllm/v1/request.py                    ✅ field added

But the API server response path was never updated:

[OutputProcessor] num_cached_tokens = N   ✅
[OpenAI Serving Layer → UsageInfo]        ❌ not mapped
[API JSON Response]                       ❌ prompt_tokens_details: null

The OpenAI serving layer (e.g. vllm/entrypoints/openai/serving_chat.py or the UsageInfo builder) does not read num_cached_tokens from RequestOutput and does not populate prompt_tokens_details.cached_tokens.

Reproduction

Server:

vllm serve facebook/opt-125m \
  --enable-prefix-caching \
  --enable-prompt-tokens-details

Client — send the same request twice (2nd should cache-hit):

# Run this twice
curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "facebook/opt-125m",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant. Please provide detailed and comprehensive answers to all questions. This is padding to ensure enough tokens for prefix caching to activate on the second request."},
      {"role": "user", "content": "What is the capital of France?"}
    ],
    "max_tokens": 20
  }' | jq '.usage'

Actual (all V1 versions):

{
  "prompt_tokens": 48,
  "total_tokens": 68,
  "completion_tokens": 20,
  "prompt_tokens_details": null
}

Expected (2nd request):

{
  "prompt_tokens": 48,
  "total_tokens": 68,
  "completion_tokens": 20,
  "prompt_tokens_details": {
    "cached_tokens": 32
  }
}

Note: /metrics confirms prefix caching is working internally — only the API response field is missing:

vllm:prefix_cache_hits_total > 0

V0 engine also returns prompt_tokens_details correctly (VLLM_USE_V1=0), confirming the gap is V1-specific.

Suggested fix

Map RequestOutput.num_cached_tokensUsageInfo.prompt_tokens_details in the OpenAI serving layer:

# Likely location: vllm/entrypoints/openai/serving_chat.py
# or wherever UsageInfo is constructed from RequestOutput

if self.enable_prompt_tokens_details and request_output.num_cached_tokens is not None:
    usage.prompt_tokens_details = PromptTokensDetails(
        cached_tokens=request_output.num_cached_tokens
    )

Impact

  • Observability: No per-request cache efficiency tracking via standard API
  • Proxy/cost tracking: LiteLLM and similar proxies rely on prompt_tokens_details.cached_tokensnull breaks cost attribution
  • OpenAI API compatibility: Violates the contract vLLM aims to fulfill
  • Duration: 14+ months since first report, all V1 versions affected

Before submitting a new issue...

  • Make sure you already searched for relevant issues, and asked the chatbot living at the bottom right corner of the documentation page, which can answer lots of frequently asked questions.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING