diff --git a/vllm/tool_parsers/qwen3coder_tool_parser.py b/vllm/tool_parsers/qwen3coder_tool_parser.py index 0285a1c07311..216ae163b77a 100644 --- a/vllm/tool_parsers/qwen3coder_tool_parser.py +++ b/vllm/tool_parsers/qwen3coder_tool_parser.py @@ -249,7 +249,10 @@ def _parse_xml_function_call( self, function_call_str: str, tools: list[ChatCompletionToolsParam] | None ) -> ToolCall | None: # Extract function name - end_index = function_call_str.index(">") + end_index = function_call_str.find(">") + # If there's no ">" character, this is not a valid xml function call + if end_index == -1: + return None function_name = function_call_str[:end_index] param_config = self._get_arguments_config(function_name, tools) parameters = function_call_str[end_index + 1 :] @@ -316,7 +319,6 @@ def extract_tool_calls( self._parse_xml_function_call(function_call_str, request.tools) for function_call_str in function_calls ] - # Populate prev_tool_call_arr for serving layer to set finish_reason self.prev_tool_call_arr.clear() # Clear previous calls for tool_call in tool_calls: @@ -333,10 +335,10 @@ def extract_tool_calls( idx = model_output.find(self.tool_call_prefix) content_index = content_index if content_index >= 0 else idx content = model_output[:content_index] # .rstrip() - + valid_tool_calls = [tc for tc in tool_calls if tc is not None] return ExtractedToolCallInformation( - tools_called=(len(tool_calls) > 0), - tool_calls=tool_calls, + tools_called=(len(valid_tool_calls) > 0), + tool_calls=valid_tool_calls, content=content if content else None, )