vllm-project/vllm · error · Error

tool_choice requires at least one available tool

Error message

tool_choice requires at least one available tool

What it means

Request validation error (`request.rs:514`): the request sets a `tool_choice` (any mode other than 'none', or a specific function choice) but the `tools` array is empty or absent. Since there is nothing to choose from, the request is rejected as a 4xx user error (`error.rs:96`).

Source

Thrown at rust/src/chat/src/error.rs:76

        selection: String,
    },
    #[error("harmony output parsing failed")]
    HarmonyOutputParsing {
        #[source]
        error: BoxedError,
    },
    #[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("chat request stream `{request_id}` closed before terminal output")]
    StreamClosedBeforeTerminalOutput { request_id: String },
    #[error("tool call stream state is inconsistent: {message}")]
    ToolCallStreamInvariant { message: String },
    #[error("duplicate tool name `{name}`")]
    DuplicateToolName { name: String },
    #[error("tool_choice requires at least one available tool")]
    ToolChoiceRequiresTools,
    #[error("tool_choice function `{name}` was not found in the available tools")]
    ToolChoiceFunctionNotFound { name: String },
    #[error("failed to build structural tag: {message}")]
    StructuralTag { message: String },
    #[error(transparent)]
    Text(#[from] vllm_text::Error),
    #[error(transparent)]
    Tokenizer(#[from] vllm_tokenizer::TokenizerError),
}

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

  1. Include at least one tool definition whenever `tool_choice` is not 'none'.
  2. If no tools are available, omit `tool_choice` entirely or set it to 'none'.
  3. Add a client-side check: `if tool_choice != none && tools.is_empty() { drop tool_choice }`.

Example fix

// before
req.tool_choice = Some(ToolChoice::Auto); // tools list empty

// after
if !tools.is_empty() {
    req.tool_choice = Some(ToolChoice::Auto);
    req.tools = tools;
}
Defensive patterns

Strategy: validation

Validate before calling

if matches!(request.tool_choice, Some(ToolChoice::Mode(_)) | Some(ToolChoice::Function(_)))
    && request.tools.as_ref().is_none_or(Vec::is_empty)
{
    return Err("tool_choice requires at least one tool");
}

Type guard

fn tool_choice_is_valid(choice: Option<&ToolChoice>, tools: &[Tool]) -> bool {
    match choice {
        None | Some(ToolChoice::Mode(Mode::None)) => true,
        Some(_) => !tools.is_empty(),
    }
}

Try / catch

match result {
    Err(vllm_chat::Error::ToolChoiceRequiresTools) => {
        respond_bad_request("set tools or change tool_choice to none")
    }
    other => other?,
}

Prevention

When it happens

Trigger: `{"tool_choice": "auto", "messages": [...]}` without a `tools` field; or `tools: []` combined with `tool_choice: {type:"function", ...}`; client code that conditionally attaches tools but always sets tool_choice.

Common situations: Dynamic agent code attaching tools only when a plugin is loaded, while hardcoding `tool_choice: "auto"`; refactoring that moved the tools field and dropped it.

Related errors


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