From b91a558c9d2e54423a83d55d607f22553d803ee7 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:11:45 +0200 Subject: [PATCH] fix: stop forwarding empty tools arrays from the Anthropic Messages endpoint (#31343) Anthropic clients such as Claude Code send "tools": [] on text-only requests like prompt-hook evaluation. The Anthropic Messages endpoint carried that empty array into the converted OpenAI request, and vLLM and the OpenAI API reject it with HTTP 400, so those requests failed while normal chats with tools kept working. A "tools": null body crashed the converter with a 500. The converter now only emits tools when the list is non-empty, and only emits tool_choice when tools were emitted. Dropping tools alone is not enough: the same backends also reject tool_choice without tools, so a request sending an empty tool list plus a tool_choice would still fail. Requests with real tools are converted exactly as before. Verified end to end against a mock backend enforcing vLLM's validation: empty, null and tool_choice-only requests went from 400/500 to 200 with end_turn, streaming included. Fixes #31341 --- backend/open_webui/utils/anthropic.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/anthropic.py b/backend/open_webui/utils/anthropic.py index 36237bdaeb..4121ba202a 100644 --- a/backend/open_webui/utils/anthropic.py +++ b/backend/open_webui/utils/anthropic.py @@ -432,8 +432,8 @@ def convert_anthropic_to_openai_payload( else: openai_payload[param] = anthropic_payload[param] - # Tools conversion: Anthropic → OpenAI - if 'tools' in anthropic_payload: + # Tools conversion: Anthropic → OpenAI (backends reject an empty tools array) + if anthropic_payload.get('tools'): openai_tools = [] for tool in anthropic_payload['tools']: openai_tools.append( @@ -452,7 +452,7 @@ def convert_anthropic_to_openai_payload( openai_payload['tools'] = openai_tools # tool_choice - if 'tool_choice' in anthropic_payload: + if 'tool_choice' in anthropic_payload and 'tools' in openai_payload: tool_choice = anthropic_payload['tool_choice'] if isinstance(tool_choice, dict): tool_choice_type = tool_choice.get('type', 'auto')