vllm - ✅(Solved) Fix [Bug]: KV Cache Read/Write Index Corruption Under Concurrent Prefill of Variable-Length Sequences (vLLM V1, FlashInfer) [1 pull requests, 1 participants]

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…
GitHub stats
vllm-project/vllm#39589Fetched 2026-04-12 13:24:33
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1labeled ×1referenced ×1subscribed ×1

After locally adopt patches from pr #37076 /pr #37152 and #39146/pr #39283, a new issue showed up, two or more concurrent requests with different prompt lengths produce non-deterministic output at temperature=0, even with Batch-invariant enabled. The same requests sent sequentially always produce identical output, indicating the model is attending to incorrect KV cache data.

Root Cause

Not floating-point / batch-composition non-determinism

  • VLLM_BATCH_INVARIANT=1 does NOT fix it. This env var forces num_splits=1 in the attention kernel, guaranteeing identical floating-point computation regardless of batch composition. Divergence persists at 11.5% (23/200 runs), ruling out floating-point precision as the root cause.
  • The logprob gap at the first diverging token is ~0.125 (top-5 tokens are within 0.25 range), which is within floating-point flip range. However, the batch-invariant test proves the divergence is NOT caused by different floating-point reduction paths, something else changes between runs.

Fix Action

Fix / Workaround

============================== CPU Info

Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian Address sizes: 48 bits physical, 48 bits virtual CPU(s): 32 On-line CPU(s) list: 0-31 Thread(s) per core: 2 Core(s) per socket: 16 Socket(s): 1 NUMA node(s): 1 Vendor ID: AuthenticAMD CPU family: 25 Model: 8 Model name: AMD Ryzen Threadripper PRO 5955WX 16-Cores Stepping: 2 Frequency boost: enabled CPU MHz: 1800.000 CPU max MHz: 7031.2500 CPU min MHz: 1800.0000 BogoMIPS: 7985.56 Virtualization: AMD-V L1d cache: 512 KiB L1i cache: 512 KiB L2 cache: 8 MiB L3 cache: 64 MiB NUMA node0 CPU(s): 0-31 Vulnerability Gather data sampling: Not affected Vulnerability Itlb multihit: Not affected Vulnerability L1tf: Not affected Vulnerability Mds: Not affected Vulnerability Meltdown: Not affected Vulnerability Mmio stale data: Not affected Vulnerability Reg file data sampling: Not affected Vulnerability Retbleed: Not affected Vulnerability Spec rstack overflow: Mitigation; safe RET, no microcode Vulnerability Spec store bypass: Mitigation; Speculative Store Bypass disabled via prctl and seccomp Vulnerability Spectre v1: Mitigation; usercopy/swapgs barriers and __user pointer sanitization Vulnerability Spectre v2: Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP always-on; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected Vulnerability Srbds: Not affected Vulnerability Tsx async abort: Not affected Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 invpcid_single hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd amd_ppin arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm

After locally adopt patches from pr #37076 /pr #37152 and #39146/pr #39283, a new issue showed up, two or more concurrent requests with different prompt lengths produce non-deterministic output at temperature=0, even with Batch-invariant enabled. The same requests sent sequentially always produce identical output, indicating the model is attending to incorrect KV cache data.

PR fix notes

PR #39591: [Bugfix] Zero block_table row tail to fix concurrent variable-length prefill non-determinism (#39589)

Description (problem / solution / changelog)

Summary

Fixes vllm-project/vllm#39589 — non-deterministic output from concurrent /v1/completions requests at temperature=0 when prompt lengths differ, on V1 + FlashInfer. The reporter observed up to 7 distinct output variants across 20 runs and confirmed the bug was not explained by FP non-determinism (VLLM_BATCH_INVARIANT=1 did not help), by prefix caching (repros with --no-enable-prefix-caching), or by the prior zero-init recycled-block fix (#39283).

Root cause

BlockTable rows are only written up to num_blocks_per_row[row_idx] and the tail is never cleared. When a persistent-batch row slot is reused by a shorter request (or becomes the tgt of move_row), stale block IDs from the previous occupant remain in the tail.

FlashInfer's _copy_page_indices_kernel (vllm/v1/attention/backends/flashinfer.py) reads block_table[req_idx, 0:num_blocks] where num_blocks comes from num_blocks_np = ceil(seq_lens_np / page_size). If that value ever exceeds the row's logical length (which can happen across concurrent variable-length prefills under persistent batching), the kernel picks up block IDs that still point at another live request's KV, and attention happily reads from the wrong request. This matches every aspect of the reported symptom: divergence starts at token 0, scales with concurrency, is insensitive to batch-invariant and prefix caching, and produces many distinct output variants (not a binary FP flip).

Fix

Zero the tail of the row (up to max_num_blocks_per_req) in:

  • BlockTable.append_row: after writing [start:end], zero [end:max_num_blocks_per_req]. Comment references #39589 so a future reader does not "optimize" it away.
  • BlockTable.move_row: after copying src → tgt, zero [num_blocks:max_num_blocks_per_req] on tgt so the previous (longer) occupant of tgt cannot leak.

The change is local, CPU-side (numpy), and paid per-request per-step on a few hundred to a few thousand int32 stores — negligible against H2D copy and kernel launch cost. append_row also switches if not block_ids to if len(block_ids) == 0 so numpy-array arguments (which raise on truthiness) are handled cleanly.

clear_row already zeros its prefix, swap_row goes through a full buffer swap, and commit_block_table copies the whole row H2D — all remain correct under the stronger invariant and need no further changes.

Why not Hypotheses B / C / D

Following the investigation plan, hypotheses B (DCP seq_lens_np / paged_kv_last_page_len inconsistency), C (persistent-batch reorder without row permutation), and D (V1 analog of #36580 slot-mapping pad bug) were either not the reporter's configuration (no DCP, no cascade), shown to be internally consistent in current V1 code, or already fixed upstream. None of them explain the reporter's symptom on their own and none are touched here.

Duplicate-work check

Per AGENTS.md §1:

gh pr list --repo vllm-project/vllm --state open --search "39589 in:body"
gh pr list --repo vllm-project/vllm --state open --search "block_table append_row tail"

Both return no open PRs as of 2026-04-11. This is not duplicating open work.

AI assistance disclosure

AI assistance (Claude) was used to investigate, write, and test this change. The submitter reviewed every changed line and ran the tests listed below.

Test plan

  • tests/v1/worker/test_block_table.py — new unit tests for the tail-zero invariant across append_row, add_row, move_row, clear_row, including:
    • Single-append, multi-append, and empty-append behavior.
    • Row reuse with a shorter new occupant (the #39589 shape).
    • move_row tail clearing when tgt previously held a longer row.
    • clear_row prefix zeroing and no-touch of sibling rows.
    • Hybrid-blocks (use_hybrid_blocks=True) path.
    • Randomized fuzz over 200-step sequences with 4 rows / 16 blocks.
    • Literal transcriptions of PLAN.md §5.1.1/5.1.2/5.1.3 named tests.
  • tests/v1/e2e/general/test_concurrent_prefill_determinism.py — end-to-end determinism regression at temperature=0 across 20 trials of a variable-length-prefill batch on Qwen/Qwen2.5-0.5B-Instruct with enforce_eager=True.
  • .venv/bin/python -m pytest tests/v1/worker/test_block_table.py -v
  • .venv/bin/python -m pytest tests/v1/worker/ tests/v1/attention/ -v
  • .venv/bin/python -m pytest tests/v1/ -k flashinfer -v
  • Upstream reproducer: 200 runs of reporter's repro_minimal.py against a local server; expected 0/200 divergences (vs. 11/200+ before the fix).
  • pre-commit run --all-files and pre-commit run mypy-3.10 --all-files --hook-stage manual.

Closes #39589

Changed files

  • tests/v1/e2e/general/test_concurrent_prefill_determinism.py (added, +47/-0)
  • tests/v1/worker/test_block_table.py (added, +700/-0)
  • vllm/v1/worker/block_table.py (modified, +14/-3)

Code Example

==============================
        System Info
==============================
OS                           : Ubuntu 20.04.6 LTS (x86_64)
GCC version                  : (Ubuntu 11.4.0-2ubuntu1~20.04) 11.4.0
Clang version                : 22.0.0 (++20251014052939+04d2b5da1ab3-1~exp1~20251014173153.1559)
CMake version                : version 3.31.7
Libc version                 : glibc-2.31

==============================
       PyTorch Info
==============================
PyTorch version              : 2.10.0+cu128
Is debug build               : False
CUDA used to build PyTorch   : 12.8
ROCM used to build PyTorch   : N/A

==============================
      Python Environment
==============================
Python version               : 3.12.8 | packaged by Anaconda, Inc. | (main, Dec 11 2024, 16:31:09) [GCC 11.2.0] (64-bit runtime)
Python platform              : Linux-5.15.0-138-generic-x86_64-with-glibc2.31

==============================
       CUDA / GPU Info
==============================
Is CUDA available            : True
CUDA runtime version         : 13.0.88
CUDA_MODULE_LOADING set to   :
GPU models and configuration :
GPU 0: NVIDIA GeForce RTX 4090
GPU 1: NVIDIA GeForce RTX 4090
GPU 2: NVIDIA GeForce RTX 4090

Nvidia driver version        : 580.126.09
cuDNN version                : Could not collect
HIP runtime version          : N/A
MIOpen runtime version       : N/A
Is XNNPACK available         : True

==============================
          CPU Info
==============================
Architecture:                         x86_64
CPU op-mode(s):                       32-bit, 64-bit
Byte Order:                           Little Endian
Address sizes:                        48 bits physical, 48 bits virtual
CPU(s):                               32
On-line CPU(s) list:                  0-31
Thread(s) per core:                   2
Core(s) per socket:                   16
Socket(s):                            1
NUMA node(s):                         1
Vendor ID:                            AuthenticAMD
CPU family:                           25
Model:                                8
Model name:                           AMD Ryzen Threadripper PRO 5955WX 16-Cores
Stepping:                             2
Frequency boost:                      enabled
CPU MHz:                              1800.000
CPU max MHz:                          7031.2500
CPU min MHz:                          1800.0000
BogoMIPS:                             7985.56
Virtualization:                       AMD-V
L1d cache:                            512 KiB
L1i cache:                            512 KiB
L2 cache:                             8 MiB
L3 cache:                             64 MiB
NUMA node0 CPU(s):                    0-31
Vulnerability Gather data sampling:   Not affected
Vulnerability Itlb multihit:          Not affected
Vulnerability L1tf:                   Not affected
Vulnerability Mds:                    Not affected
Vulnerability Meltdown:               Not affected
Vulnerability Mmio stale data:        Not affected
Vulnerability Reg file data sampling: Not affected
Vulnerability Retbleed:               Not affected
Vulnerability Spec rstack overflow:   Mitigation; safe RET, no microcode
Vulnerability Spec store bypass:      Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1:             Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:             Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP always-on; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected
Vulnerability Srbds:                  Not affected
Vulnerability Tsx async abort:        Not affected
Flags:                                fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 invpcid_single hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd amd_ppin arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm

==============================
Versions of relevant libraries
==============================
[pip3] flashinfer-python==0.6.6
[pip3] numpy==2.0.1
[pip3] nvidia-cublas-cu12==12.8.4.1
[pip3] nvidia-cuda-cupti-cu12==12.8.90
[pip3] nvidia-cuda-nvrtc-cu12==12.8.93
[pip3] nvidia-cuda-runtime-cu12==12.8.90
[pip3] nvidia-cudnn-cu12==9.10.2.21
[pip3] nvidia-cudnn-frontend==1.18.0
[pip3] nvidia-cufft-cu12==11.3.3.83
[pip3] nvidia-cufile-cu12==1.13.1.3
[pip3] nvidia-curand-cu12==10.3.9.90
[pip3] nvidia-cusolver-cu12==11.7.3.90
[pip3] nvidia-cusparse-cu12==12.5.8.93
[pip3] nvidia-cusparselt-cu12==0.7.1
[pip3] nvidia-cutlass-dsl==4.5.0.dev0
[pip3] nvidia-cutlass-dsl-libs-base==4.5.0.dev0
[pip3] nvidia-ml-py==12.570.86
[pip3] nvidia-nccl-cu12==2.27.5
[pip3] nvidia-nvjitlink-cu12==12.8.93
[pip3] nvidia-nvshmem-cu12==3.4.5
[pip3] nvidia-nvtx-cu12==12.8.90
[pip3] pyzmq==26.4.0
[pip3] torch==2.10.0
[pip3] torch_c_dlpack_ext==0.1.5
[pip3] torchaudio==2.10.0
[pip3] torchvision==0.25.0
[pip3] transformers==4.57.3
[pip3] triton==3.6.0
[conda] blas                      1.0                         mkl
[conda] cuda-cudart               12.1.105                      0    nvidia
[conda] cuda-cupti                12.1.105                      0    nvidia
[conda] cuda-libraries            12.1.0                        0    nvidia
[conda] cuda-nvrtc                12.1.105                      0    nvidia
[conda] cuda-nvtx                 12.1.105                      0    nvidia
[conda] cuda-opencl               12.6.77                       0    nvidia
[conda] cuda-runtime              12.1.0                        0    nvidia
[conda] cuda-version              12.6                          3    nvidia
[conda] ffmpeg                    4.3                  hf484d3e_0    pytorch
[conda] flashinfer-python         0.6.6                    pypi_0    pypi
[conda] libcublas                 12.1.0.26                     0    nvidia
[conda] libcufft                  11.0.2.4                      0    nvidia
[conda] libcufile                 1.11.1.6                      0    nvidia
[conda] libcurand                 10.3.7.77                     0    nvidia
[conda] libcusolver               11.4.4.55                     0    nvidia
[conda] libcusparse               12.0.2.55                     0    nvidia
[conda] libjpeg-turbo             2.0.0                h9bf148f_0    pytorch
[conda] libnpp                    12.0.2.50                     0    nvidia
[conda] libnvjitlink              12.1.105                      0    nvidia
[conda] libnvjpeg                 12.1.1.14                     0    nvidia
[conda] mkl                       2023.1.0         h213fc3f_46344
[conda] mkl-service               2.4.0           py312h5eee18b_2
[conda] mkl_fft                   1.3.11          py312h5eee18b_0
[conda] mkl_random                1.2.8           py312h526ad5a_0
[conda] numpy                     2.0.1           py312hc5e2394_1
[conda] numpy-base                2.0.1           py312h0da6c21_1
[conda] nvidia-cublas-cu12        12.8.4.1                 pypi_0    pypi
[conda] nvidia-cuda-cupti-cu12    12.8.90                  pypi_0    pypi
[conda] nvidia-cuda-nvrtc-cu12    12.8.93                  pypi_0    pypi
[conda] nvidia-cuda-runtime-cu12  12.8.90                  pypi_0    pypi
[conda] nvidia-cudnn-cu12         9.10.2.21                pypi_0    pypi
[conda] nvidia-cudnn-frontend     1.18.0                   pypi_0    pypi
[conda] nvidia-cufft-cu12         11.3.3.83                pypi_0    pypi
[conda] nvidia-cufile-cu12        1.13.1.3                 pypi_0    pypi
[conda] nvidia-curand-cu12        10.3.9.90                pypi_0    pypi
[conda] nvidia-cusolver-cu12      11.7.3.90                pypi_0    pypi
[conda] nvidia-cusparse-cu12      12.5.8.93                pypi_0    pypi
[conda] nvidia-cusparselt-cu12    0.7.1                    pypi_0    pypi
[conda] nvidia-cutlass-dsl        4.5.0.dev0               pypi_0    pypi
[conda] nvidia-cutlass-dsl-libs-base 4.5.0.dev0               pypi_0    pypi
[conda] nvidia-ml-py              12.570.86                pypi_0    pypi
[conda] nvidia-nccl-cu12          2.27.5                   pypi_0    pypi
[conda] nvidia-nvjitlink-cu12     12.8.93                  pypi_0    pypi
[conda] nvidia-nvshmem-cu12       3.4.5                    pypi_0    pypi
[conda] nvidia-nvtx-cu12          12.8.90                  pypi_0    pypi
[conda] pytorch-cuda              12.1                 ha16c6d3_6    pytorch
[conda] pytorch-mutex             1.0                        cuda    pytorch
[conda] pyzmq                     26.4.0                   pypi_0    pypi
[conda] torch                     2.10.0                   pypi_0    pypi
[conda] torch-c-dlpack-ext        0.1.5                    pypi_0    pypi
[conda] torchaudio                2.10.0                   pypi_0    pypi
[conda] torchvision               0.25.0                   pypi_0    pypi
[conda] transformers              4.57.3                   pypi_0    pypi
[conda] triton                    3.6.0                    pypi_0    pypi

==============================
         vLLM Info
==============================
ROCM Version                 : Could not collect
vLLM Version                 : 0.19.0
vLLM Build Flags:
  CUDA Archs: Not Set; ROCm: Disabled
GPU Topology:
  	GPU0	GPU1	GPU2	CPU Affinity	NUMA Affinity	GPU NUMA ID
GPU0	 X 	NODE	NODE	0-31	0		N/A
GPU1	NODE	 X 	PHB	0-31	0		N/A
GPU2	NODE	PHB	 X 	0-31	0		N/A

Legend:

  X    = Self
  SYS  = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
  NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
  PHB  = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
  PXB  = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
  PIX  = Connection traversing at most a single PCIe bridge
  NV#  = Connection traversing a bonded set of # NVLinks

==============================
     Environment Variables
==============================
TORCH_LIB=/home/yibo/miniconda3/lib/python3.12/site-packages/torch/lib
LD_LIBRARY_PATH=/home/yibo/miniconda3/lib/python3.12/site-packages/torch/lib:/usr/local/cuda/lib64:/usr/lib/x86_64-linux-gnu:/usr/local/cuda-12.2/lib64:
PYTORCH_NVML_BASED_CUDA_CHECK=1
TORCHINDUCTOR_COMPILE_THREADS=1

---

Request A: prompt_len=128, max_tokens=32, temperature=0
Request B: prompt_len=256, max_tokens=32, temperature=0
(sent simultaneously)
RAW_BUFFERClick to expand / collapse

Your current environment

<details> <summary>The output of <code>python collect_env.py</code></summary>
==============================
        System Info
==============================
OS                           : Ubuntu 20.04.6 LTS (x86_64)
GCC version                  : (Ubuntu 11.4.0-2ubuntu1~20.04) 11.4.0
Clang version                : 22.0.0 (++20251014052939+04d2b5da1ab3-1~exp1~20251014173153.1559)
CMake version                : version 3.31.7
Libc version                 : glibc-2.31

==============================
       PyTorch Info
==============================
PyTorch version              : 2.10.0+cu128
Is debug build               : False
CUDA used to build PyTorch   : 12.8
ROCM used to build PyTorch   : N/A

==============================
      Python Environment
==============================
Python version               : 3.12.8 | packaged by Anaconda, Inc. | (main, Dec 11 2024, 16:31:09) [GCC 11.2.0] (64-bit runtime)
Python platform              : Linux-5.15.0-138-generic-x86_64-with-glibc2.31

==============================
       CUDA / GPU Info
==============================
Is CUDA available            : True
CUDA runtime version         : 13.0.88
CUDA_MODULE_LOADING set to   :
GPU models and configuration :
GPU 0: NVIDIA GeForce RTX 4090
GPU 1: NVIDIA GeForce RTX 4090
GPU 2: NVIDIA GeForce RTX 4090

Nvidia driver version        : 580.126.09
cuDNN version                : Could not collect
HIP runtime version          : N/A
MIOpen runtime version       : N/A
Is XNNPACK available         : True

==============================
          CPU Info
==============================
Architecture:                         x86_64
CPU op-mode(s):                       32-bit, 64-bit
Byte Order:                           Little Endian
Address sizes:                        48 bits physical, 48 bits virtual
CPU(s):                               32
On-line CPU(s) list:                  0-31
Thread(s) per core:                   2
Core(s) per socket:                   16
Socket(s):                            1
NUMA node(s):                         1
Vendor ID:                            AuthenticAMD
CPU family:                           25
Model:                                8
Model name:                           AMD Ryzen Threadripper PRO 5955WX 16-Cores
Stepping:                             2
Frequency boost:                      enabled
CPU MHz:                              1800.000
CPU max MHz:                          7031.2500
CPU min MHz:                          1800.0000
BogoMIPS:                             7985.56
Virtualization:                       AMD-V
L1d cache:                            512 KiB
L1i cache:                            512 KiB
L2 cache:                             8 MiB
L3 cache:                             64 MiB
NUMA node0 CPU(s):                    0-31
Vulnerability Gather data sampling:   Not affected
Vulnerability Itlb multihit:          Not affected
Vulnerability L1tf:                   Not affected
Vulnerability Mds:                    Not affected
Vulnerability Meltdown:               Not affected
Vulnerability Mmio stale data:        Not affected
Vulnerability Reg file data sampling: Not affected
Vulnerability Retbleed:               Not affected
Vulnerability Spec rstack overflow:   Mitigation; safe RET, no microcode
Vulnerability Spec store bypass:      Mitigation; Speculative Store Bypass disabled via prctl and seccomp
Vulnerability Spectre v1:             Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:             Mitigation; Retpolines; IBPB conditional; IBRS_FW; STIBP always-on; RSB filling; PBRSB-eIBRS Not affected; BHI Not affected
Vulnerability Srbds:                  Not affected
Vulnerability Tsx async abort:        Not affected
Flags:                                fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 invpcid_single hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 erms invpcid cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd amd_ppin arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip pku ospke vaes vpclmulqdq rdpid overflow_recov succor smca fsrm

==============================
Versions of relevant libraries
==============================
[pip3] flashinfer-python==0.6.6
[pip3] numpy==2.0.1
[pip3] nvidia-cublas-cu12==12.8.4.1
[pip3] nvidia-cuda-cupti-cu12==12.8.90
[pip3] nvidia-cuda-nvrtc-cu12==12.8.93
[pip3] nvidia-cuda-runtime-cu12==12.8.90
[pip3] nvidia-cudnn-cu12==9.10.2.21
[pip3] nvidia-cudnn-frontend==1.18.0
[pip3] nvidia-cufft-cu12==11.3.3.83
[pip3] nvidia-cufile-cu12==1.13.1.3
[pip3] nvidia-curand-cu12==10.3.9.90
[pip3] nvidia-cusolver-cu12==11.7.3.90
[pip3] nvidia-cusparse-cu12==12.5.8.93
[pip3] nvidia-cusparselt-cu12==0.7.1
[pip3] nvidia-cutlass-dsl==4.5.0.dev0
[pip3] nvidia-cutlass-dsl-libs-base==4.5.0.dev0
[pip3] nvidia-ml-py==12.570.86
[pip3] nvidia-nccl-cu12==2.27.5
[pip3] nvidia-nvjitlink-cu12==12.8.93
[pip3] nvidia-nvshmem-cu12==3.4.5
[pip3] nvidia-nvtx-cu12==12.8.90
[pip3] pyzmq==26.4.0
[pip3] torch==2.10.0
[pip3] torch_c_dlpack_ext==0.1.5
[pip3] torchaudio==2.10.0
[pip3] torchvision==0.25.0
[pip3] transformers==4.57.3
[pip3] triton==3.6.0
[conda] blas                      1.0                         mkl
[conda] cuda-cudart               12.1.105                      0    nvidia
[conda] cuda-cupti                12.1.105                      0    nvidia
[conda] cuda-libraries            12.1.0                        0    nvidia
[conda] cuda-nvrtc                12.1.105                      0    nvidia
[conda] cuda-nvtx                 12.1.105                      0    nvidia
[conda] cuda-opencl               12.6.77                       0    nvidia
[conda] cuda-runtime              12.1.0                        0    nvidia
[conda] cuda-version              12.6                          3    nvidia
[conda] ffmpeg                    4.3                  hf484d3e_0    pytorch
[conda] flashinfer-python         0.6.6                    pypi_0    pypi
[conda] libcublas                 12.1.0.26                     0    nvidia
[conda] libcufft                  11.0.2.4                      0    nvidia
[conda] libcufile                 1.11.1.6                      0    nvidia
[conda] libcurand                 10.3.7.77                     0    nvidia
[conda] libcusolver               11.4.4.55                     0    nvidia
[conda] libcusparse               12.0.2.55                     0    nvidia
[conda] libjpeg-turbo             2.0.0                h9bf148f_0    pytorch
[conda] libnpp                    12.0.2.50                     0    nvidia
[conda] libnvjitlink              12.1.105                      0    nvidia
[conda] libnvjpeg                 12.1.1.14                     0    nvidia
[conda] mkl                       2023.1.0         h213fc3f_46344
[conda] mkl-service               2.4.0           py312h5eee18b_2
[conda] mkl_fft                   1.3.11          py312h5eee18b_0
[conda] mkl_random                1.2.8           py312h526ad5a_0
[conda] numpy                     2.0.1           py312hc5e2394_1
[conda] numpy-base                2.0.1           py312h0da6c21_1
[conda] nvidia-cublas-cu12        12.8.4.1                 pypi_0    pypi
[conda] nvidia-cuda-cupti-cu12    12.8.90                  pypi_0    pypi
[conda] nvidia-cuda-nvrtc-cu12    12.8.93                  pypi_0    pypi
[conda] nvidia-cuda-runtime-cu12  12.8.90                  pypi_0    pypi
[conda] nvidia-cudnn-cu12         9.10.2.21                pypi_0    pypi
[conda] nvidia-cudnn-frontend     1.18.0                   pypi_0    pypi
[conda] nvidia-cufft-cu12         11.3.3.83                pypi_0    pypi
[conda] nvidia-cufile-cu12        1.13.1.3                 pypi_0    pypi
[conda] nvidia-curand-cu12        10.3.9.90                pypi_0    pypi
[conda] nvidia-cusolver-cu12      11.7.3.90                pypi_0    pypi
[conda] nvidia-cusparse-cu12      12.5.8.93                pypi_0    pypi
[conda] nvidia-cusparselt-cu12    0.7.1                    pypi_0    pypi
[conda] nvidia-cutlass-dsl        4.5.0.dev0               pypi_0    pypi
[conda] nvidia-cutlass-dsl-libs-base 4.5.0.dev0               pypi_0    pypi
[conda] nvidia-ml-py              12.570.86                pypi_0    pypi
[conda] nvidia-nccl-cu12          2.27.5                   pypi_0    pypi
[conda] nvidia-nvjitlink-cu12     12.8.93                  pypi_0    pypi
[conda] nvidia-nvshmem-cu12       3.4.5                    pypi_0    pypi
[conda] nvidia-nvtx-cu12          12.8.90                  pypi_0    pypi
[conda] pytorch-cuda              12.1                 ha16c6d3_6    pytorch
[conda] pytorch-mutex             1.0                        cuda    pytorch
[conda] pyzmq                     26.4.0                   pypi_0    pypi
[conda] torch                     2.10.0                   pypi_0    pypi
[conda] torch-c-dlpack-ext        0.1.5                    pypi_0    pypi
[conda] torchaudio                2.10.0                   pypi_0    pypi
[conda] torchvision               0.25.0                   pypi_0    pypi
[conda] transformers              4.57.3                   pypi_0    pypi
[conda] triton                    3.6.0                    pypi_0    pypi

==============================
         vLLM Info
==============================
ROCM Version                 : Could not collect
vLLM Version                 : 0.19.0
vLLM Build Flags:
  CUDA Archs: Not Set; ROCm: Disabled
GPU Topology:
  	GPU0	GPU1	GPU2	CPU Affinity	NUMA Affinity	GPU NUMA ID
GPU0	 X 	NODE	NODE	0-31	0		N/A
GPU1	NODE	 X 	PHB	0-31	0		N/A
GPU2	NODE	PHB	 X 	0-31	0		N/A

Legend:

  X    = Self
  SYS  = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
  NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
  PHB  = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
  PXB  = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
  PIX  = Connection traversing at most a single PCIe bridge
  NV#  = Connection traversing a bonded set of # NVLinks

==============================
     Environment Variables
==============================
TORCH_LIB=/home/yibo/miniconda3/lib/python3.12/site-packages/torch/lib
LD_LIBRARY_PATH=/home/yibo/miniconda3/lib/python3.12/site-packages/torch/lib:/usr/local/cuda/lib64:/usr/lib/x86_64-linux-gnu:/usr/local/cuda-12.2/lib64:
PYTORCH_NVML_BASED_CUDA_CHECK=1
TORCHINDUCTOR_COMPILE_THREADS=1
</details>

🐛 Describe the bug

Summary

After locally adopt patches from pr #37076 /pr #37152 and #39146/pr #39283, a new issue showed up, two or more concurrent requests with different prompt lengths produce non-deterministic output at temperature=0, even with Batch-invariant enabled. The same requests sent sequentially always produce identical output, indicating the model is attending to incorrect KV cache data.

Minimal Reproducer

Script: repro_minimal.py Run: python3 repro_minimal.py --base-url http://localhost:8000 --runs 50

Trigger: 2 concurrent /v1/completions requests at temperature=0 with different prompt_len.

Request A: prompt_len=128, max_tokens=32, temperature=0
Request B: prompt_len=256, max_tokens=32, temperature=0
(sent simultaneously)

Divergence rate: ~8% of runs (4/50).

More Controlled Experiment Results

All tests: 50 runs, temperature=0, same prompts every run.

TestVariantsDivergence RateVerdict
2 concurrent, different size (128, 256)24/50 (8%)BUG
2 sequential, different size (128, 256)10/50 (0%)STABLE
2 concurrent, same size (128, 128)10/50 (0%)STABLE
2 concurrent, same size (1024, 1024)2+diverge / 20 runsBUG

Note: same-size (128,128) is stable, but same-size (1024,1024) also diverges. The trigger appears related to sequence length crossing block/chunk boundaries, not strictly requiring different prompt lengths.

With more concurrent requests, divergence increases dramatically:

TestVariants (worst request)Note
8 concurrent, mixed sizes (64-1024), offset=07 variants / 20 runsr08 (1024 tok)
8 concurrent, original fuzzer trace3 variants / 30 runsMultiple requests

What This Is NOT

We ruled out a few possibility:

Not a prefix caching bug

  • Tested with --no-enable-prefix-caching: still reproduces
  • Tested with default config (prefix caching on): also reproduces

Not floating-point non-determinism

  • Divergence starts at token 0, not at a single boundary token
  • Up to 7 distinct output variants in 20 runs (floating-point would give 2)
  • Sequential execution is perfectly deterministic (same GPU, same math)

Not floating-point / batch-composition non-determinism

  • VLLM_BATCH_INVARIANT=1 does NOT fix it. This env var forces num_splits=1 in the attention kernel, guaranteeing identical floating-point computation regardless of batch composition. Divergence persists at 11.5% (23/200 runs), ruling out floating-point precision as the root cause.
  • The logprob gap at the first diverging token is ~0.125 (top-5 tokens are within 0.25 range), which is within floating-point flip range. However, the batch-invariant test proves the divergence is NOT caused by different floating-point reduction paths, something else changes between runs.

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.

extent analysis

TL;DR

The issue can be mitigated by ensuring that concurrent requests with different prompt lengths are handled in a way that prevents them from accessing the same KV cache data simultaneously.

Guidance

  1. Review the attention kernel implementation: Verify that the attention kernel is correctly handling batch-invariant computations when VLLM_BATCH_INVARIANT=1. This may involve checking the num_splits variable and ensuring it is set to 1 as expected.
  2. Investigate KV cache management: Examine how the KV cache is managed and accessed by concurrent requests. Consider implementing a mechanism to prevent concurrent requests from accessing the same cache data simultaneously.
  3. Test with synchronized requests: Modify the reproducibility script to synchronize the concurrent requests, ensuring that only one request accesses the KV cache at a time. This can help determine if the issue is indeed related to concurrent access.
  4. Verify cache initialization: Confirm that the KV cache is properly initialized and reset between requests. This may involve checking the cache initialization code and ensuring that it is correctly resetting the cache state.

Example

No specific code example is provided, as the issue requires a deeper understanding of the underlying implementation. However, the following pseudo-code illustrates the idea of synchronizing concurrent requests:

import threading

# Create a lock to synchronize access to the KV cache
cache_lock = threading.Lock()

def process_request(request):
    with cache_lock:
        # Access the KV cache and perform computations
        # ...
        pass

Notes

The issue appears to be related to the interaction between concurrent requests and the KV cache. Further investigation is needed to determine the root cause and develop a comprehensive solution.

Recommendation

Apply a workaround by synchronizing concurrent requests to prevent them from accessing the same KV cache data simultaneously. This can be achieved by using locks or other synchronization primitives to ensure that only one request accesses the cache at a time.

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