{"record":{"id":"eec51416a8a25115","repo":"vllm-project/vllm","slug":"tool-choice-requires-at-least-one-available-tool","errorCode":null,"errorMessage":"tool_choice requires at least one available tool","messagePattern":"tool_choice requires at least one available tool","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"rust/src/chat/src/error.rs","lineNumber":76,"sourceCode":"        selection: String,\n    },\n    #[error(\"harmony output parsing failed\")]\n    HarmonyOutputParsing {\n        #[source]\n        error: BoxedError,\n    },\n    #[error(\n        \"this model's maximum context length is {max_model_len} tokens, \\\n         but the prompt contains {prompt_len} input tokens\"\n    )]\n    PromptTooLong { max_model_len: u32, prompt_len: u32 },\n    #[error(\"chat request stream `{request_id}` closed before terminal output\")]\n    StreamClosedBeforeTerminalOutput { request_id: String },\n    #[error(\"tool call stream state is inconsistent: {message}\")]\n    ToolCallStreamInvariant { message: String },\n    #[error(\"duplicate tool name `{name}`\")]\n    DuplicateToolName { name: String },\n    #[error(\"tool_choice requires at least one available tool\")]\n    ToolChoiceRequiresTools,\n    #[error(\"tool_choice function `{name}` was not found in the available tools\")]\n    ToolChoiceFunctionNotFound { name: String },\n    #[error(\"failed to build structural tag: {message}\")]\n    StructuralTag { message: String },\n    #[error(transparent)]\n    Text(#[from] vllm_text::Error),\n    #[error(transparent)]\n    Tokenizer(#[from] vllm_tokenizer::TokenizerError),\n}\n\npub type Result<T> = std::result::Result<T, Error>;\n\nimpl Error {\n    /// Whether this error represents invalid user request parameters.\n    pub fn is_request_validation_error(&self) -> bool {\n        match self {\n            Self::PromptTooLong { .. }","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/rust/src/chat/src/error.rs#L58-L94","documentation":"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`).","triggerScenarios":"`{\"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.","commonSituations":"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.","solutions":["Include at least one tool definition whenever `tool_choice` is not 'none'.","If no tools are available, omit `tool_choice` entirely or set it to 'none'.","Add a client-side check: `if tool_choice != none && tools.is_empty() { drop tool_choice }`."],"exampleFix":"// before\nreq.tool_choice = Some(ToolChoice::Auto); // tools list empty\n\n// after\nif !tools.is_empty() {\n    req.tool_choice = Some(ToolChoice::Auto);\n    req.tools = tools;\n}","handlingStrategy":"validation","validationCode":"if matches!(request.tool_choice, Some(ToolChoice::Mode(_)) | Some(ToolChoice::Function(_)))\n    && request.tools.as_ref().is_none_or(Vec::is_empty)\n{\n    return Err(\"tool_choice requires at least one tool\");\n}","typeGuard":"fn tool_choice_is_valid(choice: Option<&ToolChoice>, tools: &[Tool]) -> bool {\n    match choice {\n        None | Some(ToolChoice::Mode(Mode::None)) => true,\n        Some(_) => !tools.is_empty(),\n    }\n}","tryCatchPattern":"match result {\n    Err(vllm_chat::Error::ToolChoiceRequiresTools) => {\n        respond_bad_request(\"set tools or change tool_choice to none\")\n    }\n    other => other?,\n}","preventionTips":["Bind tool_choice and tools together in one request-builder method so they cannot diverge.","Default tool_choice to none when the tool list is empty."],"tags":["rust","tool-choice","validation","chat"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}