vllm-project/vllm · error · Error
`thinking_token_budget` must be a non-negative integer or -1
Error message
`thinking_token_budget` must be a non-negative integer or -1 for unlimited.
What it means
Returned by `normalize_thinking_token_budget` (rust/src/text/src/lower.rs:204-210) when the request's `thinking_token_budget` is a negative number other than the `-1` sentinel. The contract mirrors Python vLLM's `validate_thinking_token_budget`: `None` and `-1` mean unlimited, values >= 0 pass through, any other negative value is rejected. It is a request-validation error surfaced to the API caller.
Source
Thrown at rust/src/text/src/error.rs:36
#[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.")]
InvalidThinkingTokenBudget,
#[error("invalid repetition detection params: {message}")]
InvalidRepetitionDetection { message: String },
#[error("text request stream `{request_id}` closed before terminal output")]
StreamClosedBeforeTerminalOutput { request_id: String },
#[error(transparent)]
Llm(#[from] LlmError),
#[error(transparent)]
EngineCore(#[from] EngineCoreError),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
/// Whether this error represents invalid user request parameters.
pub fn is_request_validation_error(&self) -> bool {
match self {
Self::PromptTooLong { .. }View on GitHub (pinned to c794754062)
Solutions
- Use a non-negative integer for thinking_token_budget, or -1 for unlimited
- Pass null/None to leave the budget unset
- Check client-side serialization: ensure a 'disabled' flag is not encoded as an arbitrary negative number
Example fix
// before request.thinking_token_budget = -2; // intending 'no budget' // after request.thinking_token_budget = -1; // unlimited sentinel // or request.thinking_token_budget = null; // unset
Defensive patterns
Strategy: validation
Validate before calling
if let Some(budget) = request.thinking_token_budget {
assert!(budget == -1 || budget >= 0,
"thinking_token_budget must be >= 0 or -1, got {budget}");
} Type guard
fn is_invalid_thinking_budget(e: &Error) -> bool {
matches!(e, Error::InvalidThinkingTokenBudget)
} Try / catch
match lower_request(params) {
Err(Error::InvalidThinkingTokenBudget) => bad_request("thinking_token_budget must be >= 0 or -1"),
other => other,
} Prevention
- Encode 'unlimited' as exactly -1 (or null); never other negatives
- Add a client-side unit test over the budget field's serialization
When it happens
Trigger: Passing `thinking_token_budget: -2` (or any negative value besides -1) in a chat/completions request to the Rust frontend. Passing -1 is fine (unlimited); 0 and positives are fine.
Common situations: Clients using -1 from a different API's convention incorrectly (e.g. sending -2 or -100 to mean 'very large'); config templating that substitutes a negative default; serializing an Optional/int sentinel incorrectly from another language.
Related errors
- `min_tokens` must be less than or equal to `max_tokens`, got
- {parameter} must be a finite number, got {value}
- {parameter} must be in {expected}, got {value}
- max_logprobs must be non-negative or -1, got {}
- data parallel size must be at least 1
AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14).
Data as JSON: /api/errors/b61bfce6f92e5002.
Report an issue: GitHub.