{"record":{"id":"edbb31c8c5b25423","repo":"PrefectHQ/fastmcp","slug":"unsupported-tool-choice-mode-tool-choice-mode-r-edbb31","errorCode":null,"errorMessage":"Unsupported tool_choice mode: {tool_choice.mode!r}","messagePattern":"Unsupported tool_choice mode: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/client/sampling/handlers/openai.py","lineNumber":449,"sourceCode":"                        parameters=parameters,\n                    ),\n                )\n            )\n        return openai_tools\n\n    @staticmethod\n    def _convert_tool_choice_to_openai(\n        tool_choice: ToolChoice,\n    ) -> ChatCompletionToolChoiceOptionParam:\n        \"\"\"Convert MCP tool_choice to OpenAI format.\"\"\"\n        if tool_choice.mode == \"auto\":\n            return \"auto\"\n        elif tool_choice.mode == \"required\":\n            return \"required\"\n        elif tool_choice.mode == \"none\":\n            return \"none\"\n        else:\n            raise ValueError(f\"Unsupported tool_choice mode: {tool_choice.mode!r}\")\n\n    @staticmethod\n    def _chat_completion_to_result_with_tools(\n        chat_completion: ChatCompletion,\n    ) -> CreateMessageResultWithTools:\n        \"\"\"Convert OpenAI response to CreateMessageResultWithTools.\"\"\"\n        if len(chat_completion.choices) == 0:\n            raise ValueError(\"No response for completion\")\n\n        first_choice = chat_completion.choices[0]\n        message = first_choice.message\n\n        # Determine stop reason\n        stop_reason: StopReason\n        if first_choice.finish_reason == \"tool_calls\":\n            stop_reason = \"toolUse\"\n        elif first_choice.finish_reason == \"stop\":\n            stop_reason = \"endTurn\"","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/client/sampling/handlers/openai.py#L431-L467","documentation":"_convert_tool_choice_to_openai maps MCP ToolChoice modes 'auto', 'required', and 'none' to OpenAI tool_choice values. Any other mode string has no OpenAI equivalent and raises this ValueError with the offending mode repr.","triggerScenarios":"Calling the OpenAI sampling handler with a ToolChoice whose mode is not one of 'auto'/'required'/'none' — e.g. a provider-specific mode like 'any' or 'forced_function' carried over from another backend.","commonSituations":"Reusing tool_choice objects built for Anthropic-style handlers ('any' mode) with the OpenAI handler; config files with typo'd mode values; newer MCP SDK adding a mode enum member the handler hasn't mapped yet.","solutions":["Set tool_choice.mode to 'auto', 'required', or 'none' before invoking the OpenAI handler.","If you need 'force a specific function', pass the target tool name via sampling params the OpenAI path supports, or map it to 'required' plus prompt guidance.","Translate Anthropic-style modes ('any' -> 'required') in an adapter before calling.","Catch ValueError and default to 'auto' when strict forcing is not required."],"exampleFix":"// before\nToolChoice(mode='any')  # anthropic-style\n// after\nToolChoice(mode='required')","handlingStrategy":"validation","validationCode":"VALID_MODES = {'auto', 'required', 'none'}\ndef assert_valid_tool_choice(tool_choice):\n    if tool_choice is not None and tool_choice.mode not in VALID_MODES:\n        raise ValueError(f'mode {tool_choice.mode!r} unsupported by OpenAI handler; use auto/required/none')","typeGuard":"def is_openai_compatible_tool_choice(tc) -> bool:\n    return tc is None or getattr(tc, 'mode', None) in {'auto', 'required', 'none'}","tryCatchPattern":"try:\n    result = await openai_handler(messages, params)\nexcept ValueError as e:\n    if str(e).startswith('Unsupported tool_choice mode'):\n        params.toolChoice = ToolChoice(mode='auto')\n        result = await openai_handler(messages, params)\n    else:\n        raise","preventionTips":["Restrict tool_choice modes to auto/required/none for OpenAI","Map provider-specific modes ('any') in an adapter layer","Validate ToolChoice at config-load time, not at request time","Add unit tests for every tool_choice mode you use"],"tags":["openai","sampling","tool-choice","validation"],"backgroundTag":"unsupported-parameter-value","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}