Skip to content

fix(logprobs): guard convert_ids_list_to_tokens against out-of-range ids#48567

Open
UranusSeven wants to merge 2 commits into
vllm-project:mainfrom
UranusSeven:fix/prompt-logprobs-overflow-out-of-range-token-id
Open

fix(logprobs): guard convert_ids_list_to_tokens against out-of-range ids#48567
UranusSeven wants to merge 2 commits into
vllm-project:mainfrom
UranusSeven:fix/prompt-logprobs-overflow-out-of-range-token-id

Conversation

@UranusSeven

@UranusSeven UranusSeven commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

convert_ids_list_to_tokens in vllm/tokenizers/detokenizer_utils.py calls tokenizer.decode([token_id]) for every id with no bounds check. When an out-of-range id (negative, or beyond the u32 range) reaches a fast/rust-backed tokenizer, the rust binding raises OverflowError: out of range integral type conversion attempted while converting the Python int to a u32. Such ids can surface in uninitialized slots of the chunked prompt-logprobs tensor (LogprobsTensors.empty_cpu uses torch.empty, filled slice-by-slice across prefill chunks), crashing the async output handler.

detokenize_incrementally in the same file already guards this exact case with if 0 <= new_token_id < len(tokenizer), but convert_ids_list_to_tokens — used by both sample and prompt logprobs — was missing the equivalent guard.

Fix

Mirror the existing 0 <= id < len(tokenizer) guard: out-of-range ids decode to "" instead of being passed to the tokenizer. Since the result is empty (no U+FFFD), it does not perturb the downstream byte-fallback UTF-8 correction path.

Test plan

  • Added test_convert_ids_list_to_tokens_out_of_range (parametrized over -1, -12345, 2**32, 2**63) using a fake rust-like tokenizer that raises OverflowError on out-of-range ids; asserts the result is [""].

Prompt logprobs handling crashed the async output handler with
OverflowError: out of range integral type conversion attempted when an
out-of-range token id (negative or beyond u32) reached the fast
tokenizer's decode. Such ids can appear in uninitialized slots of the
chunked prompt-logprobs tensor. Mirror the 0 <= id < len(tokenizer)
guard already used in detokenize_incrementally so these ids decode to
"" instead of raising.

Co-authored-by: Claude
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>

Signed-off-by: UranusSeven <109661872+UranusSeven@users.noreply.github.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

# Out-of-range ids (e.g. uninitialized prompt-logprobs slots) make a
# fast tokenizer's u32 conversion raise OverflowError; guard like
# detokenize_incrementally does.
if not 0 <= token_id < vocab_size:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Out of range IDs shouldn't get passed here in the first place, right?

cc @njhill

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, @UranusSeven could you explain more about how you encountered this?

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.

This happened in prod, leading to a decoder crash. The whole stack:

ERROR 07-12 06:47:23 [async_llm.py:706] Traceback (most recent call last):
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../vllm/v1/engine/async_llm.py", line 677, in output_handler
ERROR 07-12 06:47:23 [async_llm.py:706]     processed_outputs = output_processor.process_outputs(
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../vllm/v1/engine/output_processor.py", line 655, in process_outputs
ERROR 07-12 06:47:23 [async_llm.py:706]     req_state.logprobs_processor.update_from_output(engine_core_output)
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../vllm/v1/engine/logprobs.py", line 352, in update_from_output
ERROR 07-12 06:47:23 [async_llm.py:706]     self._update_prompt_logprobs(output.new_prompt_logprobs_tensors)
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../vllm/v1/engine/logprobs.py", line 147, in _update_prompt_logprobs
ERROR 07-12 06:47:23 [async_llm.py:706]     else convert_ids_list_to_tokens(
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../vllm/tokenizers/detokenizer_utils.py", line 100, in convert_ids_list_to_tokens
ERROR 07-12 06:47:23 [async_llm.py:706]     token_str = tokenizer.decode([token_id])
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../vllm/tokenizers/hf.py", line 86, in decode
ERROR 07-12 06:47:23 [async_llm.py:706]     return tok.decode(*args, **kwargs)
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../transformers/tokenization_utils_base.py", line 2897, in decode
ERROR 07-12 06:47:23 [async_llm.py:706]     return self._decode(
ERROR 07-12 06:47:23 [async_llm.py:706]   File ".../transformers/tokenization_utils_tokenizers.py", line 1032, in _decode
ERROR 07-12 06:47:23 [async_llm.py:706]     text = self._tokenizer.decode(token_ids, skip_special_tokens=skip_special_tokens)
ERROR 07-12 06:47:23 [async_llm.py:706] OverflowError: out of range integral type conversion attempted
ERROR 07-12 06:47:23 [serving.py:1004] Error in chat completion stream generator.

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.

vLLM was v0.23.0.

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.

Drive by comment @DarkLight1337 @njhill #47346 similar issue and fix.

Yes, we shouldn't have out of range IDs here, but if we do have a model regression spitting out invalid token IDs, we currently get a fairly misleading tokenizer crash.

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.

4 participants