vllm-project/vllm · error · Error

text request `{request_id}` stop strings cannot be empty

Error message

text request `{request_id}` stop strings cannot be empty

What it means

Error variant raised in rust/src/text/src/request.rs:238 when a request's stop strings list contains an empty string. An empty stop string would match at every position and terminate generation immediately, so it is rejected as an invalid request parameter. Like the other request-shape errors, it maps to a client-side validation error.

Source

Thrown at rust/src/text/src/error.rs:18

// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright contributors to the vLLM project

use thiserror::Error;
use vllm_engine_core_client::Error as EngineCoreError;
use vllm_llm::Error as LlmError;

pub use crate::lower::logprobs::LogprobsError;
pub use crate::lower::sampling::SamplingParamsError;
pub use crate::lower::token_ids::TokenIdsError;

#[derive(Debug, Error)]
pub enum Error {
    #[error("tokenizer error: {0}")]
    Tokenizer(String),
    #[error("text request `{request_id}` must contain at least one prompt token ID")]
    EmptyPromptTokenIds { request_id: String },
    #[error("text request `{request_id}` stop strings cannot be empty")]
    EmptyStopString { request_id: String },
    #[error(
        "this model's maximum context length is {max_model_len} tokens, \
         but the prompt contains {prompt_len} input tokens"
    )]
    PromptTooLong { max_model_len: u32, prompt_len: u32 },
    #[error(transparent)]
    Logprobs(#[from] LogprobsError),
    #[error(transparent)]
    TokenIds(#[from] TokenIdsError),
    #[error(transparent)]
    SamplingParams(#[from] SamplingParamsError),
    #[error(
        "`min_tokens` must be less than or equal to `max_tokens`, \
         got min_tokens={min_tokens}, max_tokens={max_tokens}"
    )]
    MinTokensExceedsMaxTokens { min_tokens: u32, max_tokens: u32 },
    #[error("`thinking_token_budget` must be a non-negative integer or -1 for unlimited.")]

View on GitHub (pinned to c794754062)

Solutions

  1. Remove empty strings from the stop array before sending.
  2. Filter in client code: stop.filter(|s| !s.is_empty()).
  3. If you need 'stop on anything', omit the stop parameter rather than passing empty strings.

Example fix

# before
{"prompt": "hi", "stop": ["\n", ""]}

# after
{"prompt": "hi", "stop": ["\n"]}
Defensive patterns

Strategy: validation

Validate before calling

stop.retain(|s| !s.is_empty());
if stop.is_empty() { stop = None; }

Type guard

fn stop_list_is_valid(stop: &[String]) -> bool {
    stop.iter().all(|s| !s.is_empty())
}

Try / catch

match result {
    Err(e @ vllm_text::Error::EmptyStopString { .. }) => respond_400(e),
    other => other,
}

Prevention

When it happens

Trigger: POST to completions/chat with "stop": [""] or "stop": ["\n", ""] — any empty element in the stop array. Also occurs when client code joins/splits stop lists and leaves an empty residue.

Common situations: Building stop lists from user input without filtering empties (e.g. "\n, ,END".split(',')); appending an optional stop that was never set; JSON deserialization of stop as a list where an empty default slipped in.

Related errors


AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14). Data as JSON: /api/errors/8c4e24255f956874. Report an issue: GitHub.