Skip to content

[Bugfix] [Parser] Fix Qwen3 latent bug in partial params dropping values containing < - #46047

Merged
sfeng33 merged 1 commit into
vllm-project:mainfrom
bbrowning:qwen-parser-angle-bracket
Jun 18, 2026
Merged

sfeng33 merged 1 commit into
vllm-project:mainfrom
bbrowning:qwen-parser-angle-bracket

Conversation

@bbrowning

Copy link
Copy Markdown
Contributor

Purpose

In the new Qwen3 parser, _PARTIAL_PARAM_RE used [^<]*$ to capture in-progress parameter content. When a value contained a literal < (HTML, code, math like x<5), the regex failed to match entirely. In practice this appears to be handled gracefully by the holdback mechanism. But, it is a latent bug even though I have not been able to trigger that in the real world so far outside of the unit tests here. There could be some specific scenario of generated arguments that triggers this in a live server, so better to clean this up before users hit it.

Fix by changing [^<]*$ to (.*)$ so the capture group accepts any character including <.

Test Plan

Unit Tests

I added a couple unit tests specifically to reproduce. The test plan below runs those as well as all other parser engine, qwen3 and nemotron_v3 reasoning tests (because the nemotron parser inherits from the qwen one).

pytest -v \
  tests/parser/engine/ \
  tests/reasoning/test_qwen3_reasoning_parser.py \
  tests/reasoning/test_nemotron_v3_reasoning_parser.py \
  tests/tool_parsers/test_qwen3coder_tool_parser.py

Test Result

Unit Tests

1762 passed, 2 warnings

…ining <

_PARTIAL_PARAM_RE used [^<]*$ to capture in-progress parameter content.
When a value contained a literal < (HTML, code, math like x<5), the
regex failed to match entirely, silently dropping the parameter during
streaming.

Fix by changing [^<]*$ to (.*)$ so the capture group accepts any
character including <.

Co-Authored-By: Claude <noreply@anthropic.com>

Signed-off-by: Ben Browning <bbrownin@redhat.com>
@mergify mergify Bot added qwen Related to Qwen models tool-calling bug Something isn't working labels Jun 18, 2026
@sfeng33 sfeng33 added the ready ONLY add when PR is ready to merge/full CI is needed label Jun 18, 2026
@sfeng33
sfeng33 enabled auto-merge (squash) June 18, 2026 15:31
@sfeng33
sfeng33 merged commit 09f3cd5 into vllm-project:main Jun 18, 2026
57 checks passed
@bbrowning
bbrowning deleted the qwen-parser-angle-bracket branch June 18, 2026 18:24
nkzhenhua pushed a commit to nkzhenhua/vllm that referenced this pull request Jun 24, 2026
…ues containing `<` (vllm-project#46047)

Signed-off-by: Ben Browning <bbrownin@redhat.com>
philippesic pushed a commit to philippesic/vllm-semantic-cache that referenced this pull request Jul 19, 2026
…ues containing `<` (vllm-project#46047)

Signed-off-by: Ben Browning <bbrownin@redhat.com>
W-Schmitt added a commit to W-Schmitt/vllm that referenced this pull request Aug 21, 2026
…ool call arguments

The _PARTIAL_PARAM_RE regex in vllm/parser/deepseek_v4.py used a greedy
(.*)$ capture that swallowed partial DSML closing tags (e.g.
Paris</|DSML|parameter without the final >) into parameter values during
streaming. When _compute_arg_delta called _dsml_arg_converter with
partial=True on slot.args containing such a partial closing tag, the
converter captured the tag text as part of the parameter value. The
_safe_arg_prefix method then streamed the unterminated string content
(including DSML markup) as a tool call argument delta.

Replace the greedy capture with a tempered greedy token using a negative
lookahead that stops at DSML tag prefixes:
((?:(?!</?{_ESCAPED_DSML}).)*)

This preserves the ability to capture literal < in values (the concern
from vllm-project#46047) while preventing partial DSML closing tags from leaking into
parameter values.

The bug was introduced in vllm-project#45877 which ported DeepSeek V4 from the
hand-written DeepSeekV32ToolParser to the StreamingParserEngine framework.
The old parser used a buffer-and-split approach that searched for the
complete closing tag string as a boundary and never ran a regex on partial
args.

Verified on a live 8xH200 deployment: all streaming tool call tests
produce clean JSON arguments with no DSML leakage after the fix.

Co-authored-by: GLM5.2
Signed-off-by: William Schmitt <w.schmitt@criteo.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working qwen Related to Qwen models ready ONLY add when PR is ready to merge/full CI is needed tool-calling

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants