{"record":{"id":"0efac4136c868a13","repo":"microsoft/autogen","slug":"tool-choice-required-specified-but-no-tools-prov","errorCode":null,"errorMessage":"tool_choice 'required' specified but no tools provided","messagePattern":"tool_choice 'required' specified but no tools provided","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/models/ollama/_ollama_client.py","lineNumber":601,"sourceCode":"        ollama_messages = [item for sublist in ollama_messages_nested for item in sublist]\n\n        if self.model_info[\"function_calling\"] is False and len(tools) > 0:\n            raise ValueError(\"Model does not support function calling and tools were provided\")\n\n        converted_tools: List[OllamaTool] = []\n\n        # Handle tool_choice parameter in a way that is compatible with Ollama API.\n        if isinstance(tool_choice, Tool):\n            # If tool_choice is a Tool, convert it to OllamaTool.\n            converted_tools = convert_tools([tool_choice])\n        elif tool_choice == \"none\":\n            # No tool choice, do not pass tools to the API.\n            converted_tools = []\n        elif tool_choice == \"required\":\n            # Required tool choice, pass tools to the API.\n            converted_tools = convert_tools(tools)\n            if len(converted_tools) == 0:\n                raise ValueError(\"tool_choice 'required' specified but no tools provided\")\n        else:\n            converted_tools = convert_tools(tools)\n\n        return CreateParams(\n            messages=ollama_messages,\n            tools=converted_tools,\n            format=response_format_value,\n            create_args=create_args,\n        )\n\n    async def create(\n        self,\n        messages: Sequence[LLMMessage],\n        *,\n        tools: Sequence[Tool | ToolSchema] = [],\n        tool_choice: Tool | Literal[\"auto\", \"required\", \"none\"] = \"auto\",\n        json_output: Optional[bool | type[BaseModel]] = None,\n        extra_create_args: Mapping[str, Any] = {},","sourceCodeStart":583,"sourceCodeEnd":619,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/models/ollama/_ollama_client.py#L583-L619","documentation":"When tool_choice='required' is passed to OllamaChatCompletionClient.create(), the client converts the tools list to Ollama's tool format. If that conversion yields an empty list (i.e. no usable tools were provided), it raises ValueError because 'required' tool choice is meaningless without tools. The client refuses to send a contradictory request to Ollama.","triggerScenarios":"Calling create(messages, tools=[], tool_choice='required') or passing tool_choice='required' with a tools sequence that converts to zero Ollama tools (e.g. empty list, or entries convert_tools drops).","commonSituations":"Agent code that always sets tool_choice='required' but dynamically builds the tools list, which can be empty on some turns; refactoring that accidentally drops the tools argument while keeping tool_choice; copy-paste from an example that used a fixed tool set.","solutions":["Pass a non-empty tools list whenever tool_choice='required' is set","Guard the call: only set tool_choice='required' when len(tools) > 0, otherwise use 'auto' or omit it","Fix upstream logic that produces an empty tools list when it should not be empty"],"exampleFix":"# before\nawait client.create(messages, tools=filtered_tools, tool_choice='required')  # crashes when filtered_tools == []\n\n# after\ntool_choice = 'required' if tools else 'auto'\nawait client.create(messages, tools=tools, tool_choice=tool_choice)","handlingStrategy":"type-guard","validationCode":"if tool_choice == 'required' and len(tools) == 0:\n    tool_choice = 'auto'  # or raise your own config error\nresult = await client.create(messages, tools=tools, tool_choice=tool_choice)","typeGuard":"from typing import Any\n\ndef valid_tool_choice(tool_choice: Any, tools) -> bool:\n    if tool_choice == 'required':\n        return len(tools) > 0\n    return tool_choice in ('auto', 'none') or hasattr(tool_choice, 'schema')","tryCatchPattern":"try:\n    result = await client.create(messages, tools=tools, tool_choice='required')\nexcept ValueError as e:\n    if \"'required' specified but no tools\" in str(e):\n        result = await client.create(messages, tools=tools, tool_choice='auto')\n    else:\n        raise","preventionTips":["Never set tool_choice='required' without checking tools is non-empty","Assert invariants in agent loops that compute tools dynamically","Prefer 'auto' unless forced-call semantics are truly required"],"tags":["ollama","tool-choice","validation","autogen"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}