{"record":{"id":"a285f074cb096dfc","repo":"sgl-project/sglang","slug":"tool-choice-references-tool-tool-name-r-but-it-i","errorCode":null,"errorMessage":"tool_choice references tool {tool_name!r} but it is not in the forwarded tools list (server-side Anthropic tools cannot be selected)","messagePattern":"tool_choice references tool (.+?) but it is not in the forwarded tools list \\(server-side Anthropic tools cannot be selected\\)","errorType":"http","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"python/sglang/srt/entrypoints/anthropic/serving.py","lineNumber":714,"sourceCode":"        if anthropic_request.tool_choice is not None:\n            tc_type = anthropic_request.tool_choice.type\n            if tc_type == \"none\":\n                chat_request.tool_choice = \"none\"\n            elif chat_request.tools:\n                if tc_type == \"auto\":\n                    chat_request.tool_choice = \"auto\"\n                elif tc_type == \"any\":\n                    chat_request.tool_choice = \"required\"\n                elif tc_type == \"tool\":\n                    tool_name = anthropic_request.tool_choice.name\n                    # ``Tool.function`` is a ``Function`` Pydantic model, not\n                    # a dict — access by attribute. A dict ``.get`` would\n                    # AttributeError and surface as a 500 instead of the\n                    # intended 400 / happy path.\n                    if not any(\n                        t.function.name == tool_name for t in chat_request.tools\n                    ):\n                        raise ValueError(\n                            f\"tool_choice references tool {tool_name!r} but it \"\n                            f\"is not in the forwarded tools list \"\n                            f\"(server-side Anthropic tools cannot be selected)\"\n                        )\n                    chat_request.tool_choice = ToolChoice(\n                        type=\"function\",\n                        function=ToolChoiceFuncName(name=tool_name),\n                    )\n            elif tc_type in (\"any\", \"tool\"):\n                raise ValueError(\n                    f\"tool_choice={tc_type!r} requires at least one custom \"\n                    f\"tool; all supplied tools were server-side Anthropic \"\n                    f\"built-ins which the OpenAI-compatible backend cannot \"\n                    f\"invoke\"\n                )\n        elif chat_request.tools:\n            chat_request.tool_choice = \"auto\"\n","sourceCodeStart":696,"sourceCodeEnd":732,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/entrypoints/anthropic/serving.py#L696-L732","documentation":"Raised during Anthropic-to-OpenAI-compatible request conversion when tool_choice names a specific tool (type='tool' with a name, or the legacy 'function' form) that is not present in the request's tools list. SGLang only forwards client-supplied custom tools to the backend; server-side Anthropic built-in tools (web_search, code_execution, etc.) cannot be selected, so an unmatched name is a 400.","triggerScenarios":"POST /v1/messages with tool_choice={\"type\": \"tool\", \"name\": \"get_weather\"} where no tool named get_weather appears in the tools array; or tool_choice naming an Anthropic built-in like web_search_20250305.","commonSituations":"Typos or case mismatches between tool name and tool_choice name; assuming built-in Anthropic tools can be force-selected; frontend and backend tool definitions drifting out of sync.","solutions":["Make tool_choice.name exactly match a tool's name field in the same request's tools array","Do not reference server-side Anthropic built-in tools in tool_choice — define a custom tool instead","Use tool_choice type 'auto' if you don't need to force a specific tool"],"exampleFix":"// before\n{\"tools\": [{\"name\": \"get_weather\", ...}], \"tool_choice\": {\"type\": \"tool\", \"name\": \"GetWeather\"}}\n// after\n{\"tools\": [{\"name\": \"get_weather\", ...}], \"tool_choice\": {\"type\": \"tool\", \"name\": \"get_weather\"}}","handlingStrategy":"validation","validationCode":"names = {t.get(\"name\") for t in tools if t.get(\"type\") in (\"custom\", \"function\")}\nif tool_choice.get(\"type\") == \"tool\" and tool_choice.get(\"name\") not in names:\n    raise ValueError(\"tool_choice.name must match a custom tool name\")","typeGuard":"def tool_choice_is_valid(tool_choice, tools) -> bool:\n    if tool_choice.get(\"type\") != \"tool\": return True\n    return tool_choice.get(\"name\") in {t.get(\"name\") for t in tools}","tryCatchPattern":"try: resp = client.messages.create(...)\nexcept ValueError as e:\n    if 'tool_choice references tool' in str(e): fix_name_and_retry()","preventionTips":["Derive tool_choice.name from the tools array programmatically","Remember built-in Anthropic tools can't be selected"],"tags":["anthropic","tool-choice","tools","validation","request-conversion"],"backgroundTag":"tool-choice-mismatch","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}