litellm - ✅(Solved) Fix [Bug]: tools are required when tool choice is specified when using claude code's web search skill via litellm proxy [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
BerriAI/litellm#25477Fetched 2026-04-11 06:14:07
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
0
Author
Participants
Timeline (top)
labeled ×4cross-referenced ×1referenced ×1

Error Message

Using claude code's web search always return 0 results, and litellm gave an error: tools are required when tool choice is specified. But normal chat like `curl -X POST http://localhost:4444/chat/completions
14:37:14 - LiteLLM Proxy:ERROR: endpoints.py:121 - litellm.proxy.proxy_server.anthropic_response(): Exception occured - litellm.BadRequestError: Github_copilotException - tools are required when tool choice is specified. Received Model Group=claude-haiku-4-5 Traceback (most recent call last): openai.BadRequestError: Error code: 400 - {'error': {'message': 'tools are required when tool choice is specified', 'code': 'invalid_request_body'}} During handling of the above exception, another exception occurred: Traceback (most recent call last): litellm.llms.openai.common_utils.OpenAIError: Error code: 400 - {'error': {'message': 'tools are required when tool choice is specified', 'code': 'invalid_request_body'}} During handling of the above exception, another exception occurred: Traceback (most recent call last): error=e, raise error

Fix Action

Fixed

PR fix notes

PR #25515: fix(anthropic): drop orphan tool_choice when tools array is empty

Description (problem / solution / changelog)

Fixes #25477

Description

Hi there! I noticed that when proxy logic (like websearch_interception) removes tools from the tools array, the tool_choice parameter sometimes gets left behind. Anthropic's API seems to return a 400 error (BadRequestError) when it receives a tool_choice without any tools.

To try and help with this, this PR simply removes the tool_choice parameter in AnthropicConfig.map_openai_params if the tools list happens to be empty. Hopefully, this helps prevent the error.

Before Logs

I ran a small test script to see what happens when tool_choice is passed but tools is empty.

Command line:

$ python3 test_issue_25477.py

Output (before_test.log):

MAPPED PARAMS:
{'tool_choice': {'type': 'tool', 'name': 'google_search_tool'}, 'tools': []}

[BUG REPRODUCED]: `tool_choice` was passed to Anthropic without `tools`. This causes an Anthropic 400 BadRequestError!

After Logs

After the small change, here is what happens:

Command line:

$ python3 test_issue_25477.py

Output (after_test.log):

MAPPED PARAMS:
{'tools': []}

[SUCCESS]: `tool_choice` is correctly handled when `tools` are missing or empty.

Thanks so much for taking a look, and please let me know if any other changes are needed!

Changed files

  • litellm/llms/anthropic/chat/transformation.py (modified, +5/-0)

Code Example

3. Configure litellm to use github copilot as model provider

---

4. Start litellm with `litellm --config copilot-config.yaml --port 4444`
4. Start `claude`, chat something like `use the web search tool to read litellm doc`
5. Check the log output in claude code and litellm


### Relevant log output
RAW_BUFFERClick to expand / collapse

Check for existing issues

  • I have searched the existing issues and checked that my issue is not a duplicate.

What happened?

Using claude code's web search always return 0 results, and litellm gave an error: tools are required when tool choice is specified. But normal chat like curl -X POST http://localhost:4444/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $$(grep LITELLM_MASTER_KEY .env | cut -d'=' -f2 | tr -d '\"')" \ -d '{"model": "claude-sonnet-4", "messages": [{"role": "user", "content": "Hello"}]}' worked.

I've read the doc about web search interceptor to intercept the web search implementation to other search providers. But I still like to know if there is a way to fix this issue.

Steps to Reproduce

  1. Install claude code 2.1.100
  2. Configure the claude code to use litellm
"env": {
    "ANTHROPIC_AUTH_TOKEN": "litellm-<xxxx>",
    "ANTHROPIC_BASE_URL": "http://localhost:4444",
    "ANTHROPIC_MODEL": "claude-sonnet-4-5",
    "ANTHROPIC_SMALL_FAST_MODEL": "claude-haiku-4-5"
  },
  1. Configure litellm to use github copilot as model provider
litellm_settings:
  set_verbose: false

model_list:
  - model_name: claude-3-5-sonnet-20241022
    litellm_params:
      model: github_copilot/claude-sonnet-4.6 
      additional_drop_params: ["thinking"] 
      extra_headers: &copilot_headers
        Editor-Version: "vscode/1.85.1"
        Copilot-Integration-Id: "vscode-chat"
  - model_name: claude-sonnet-4
    litellm_params:
      model: github_copilot/claude-sonnet-4 
      additional_drop_params: ["thinking"] 
      extra_headers: *copilot_headers

  - model_name: claude-opus-4
    litellm_params:
      model: github_copilot/claude-opus-4.6
      additional_drop_params: ["thinking"] 
      extra_headers: *copilot_headers

    # Claude Opus 4.6 (Anthropic) - Max tokens: 64000, Context: 200000
  - model_name: claude-opus-4-6  
    litellm_params:
      model: github_copilot/claude-opus-4.6
      additional_drop_params: ["thinking"] # 👈 KEY CHANGE
      extra_headers: *copilot_headers

    # Claude Sonnet 4.6 (Anthropic) - Max tokens: 32000, Context: 200000
  - model_name: claude-sonnet-4-6  
    litellm_params:
      model: github_copilot/claude-sonnet-4.6
      additional_drop_params: ["thinking"] 
      extra_headers: *copilot_headers

    # Claude Sonnet 4.5 (Anthropic) - Max tokens: 32000, Context: 144000
  - model_name: claude-sonnet-4-5  
    litellm_params:
      model: github_copilot/claude-sonnet-4.5
      additional_drop_params: ["thinking"] 
      extra_headers: *copilot_headers

    # Claude Opus 4.5 (Anthropic) - Max tokens: 32000, Context: 160000
  - model_name: claude-opus-4-5  
    litellm_params:
      model: github_copilot/claude-opus-4.5
      additional_drop_params: ["thinking"] 
      extra_headers: *copilot_headers

    # Claude Haiku 4.5 (Anthropic) - Max tokens: 32000, Context: 144000
  - model_name: claude-haiku-4-5  
    litellm_params:
      model: github_copilot/claude-haiku-4.5
      additional_drop_params: ["thinking"] 
      extra_headers: *copilot_headers

  - model_name: gemini-3-1-pro-preview
    litellm_params:
      model: github_copilot/gemini-3.1-pro-preview
      extra_headers: *copilot_headers
    # Gemini 3.1 Pro (Google) - Max tokens: 64000, Context: 128000

  - model_name: gemini-3-pro-preview
    litellm_params:
      model: github_copilot/gemini-3-pro-preview
      extra_headers: *copilot_headers
    # Gemini 3 Pro Preview (Google) - Max tokens: 64000, Context: 128000

  - model_name: gemini-3-flash-preview
    litellm_params:
      model: github_copilot/gemini-3-flash-preview
      extra_headers: *copilot_headers
    # Gemini 3 Flash Preview (Google) - Max tokens: 64000, Context: 128000

  - model_name: gemini-2-5-pro
    litellm_params:
      model: github_copilot/gemini-2.5-pro
      extra_headers: *copilot_headers
    # Gemini 2.5 Pro (Google) - Max tokens: 64000, Context: 128000


  - model_name: gpt-5-2-codex
    litellm_params:
      model: github_copilot/gpt-5.2-codex
      extra_headers: *copilot_headers
    # GPT-5.2-Codex (OpenAI) - Max tokens: 128000, Context: 400000

  - model_name: gpt-5-3-codex
    litellm_params:
      model: github_copilot/gpt-5.3-codex
      extra_headers: *copilot_headers
    # GPT-5.3-Codex (OpenAI) - Max tokens: 128000, Context: 400000

  - model_name: gpt-5-1
    litellm_params:
      model: github_copilot/gpt-5.1
      extra_headers: *copilot_headers
    # GPT-5.1 (OpenAI) - Max tokens: 64000, Context: 264000

  - model_name: gpt-5-1-codex
    litellm_params:
      model: github_copilot/gpt-5.1-codex
      extra_headers: *copilot_headers
    # GPT-5.1-Codex (OpenAI) - Max tokens: 128000, Context: 400000

  - model_name: gpt-5-1-codex-mini
    litellm_params:
      model: github_copilot/gpt-5.1-codex-mini
      extra_headers: *copilot_headers
    # GPT-5.1-Codex-Mini (OpenAI) - Max tokens: 128000, Context: 400000

  - model_name: gpt-5-1-codex-max
    litellm_params:
      model: github_copilot/gpt-5.1-codex-max
      extra_headers: *copilot_headers
    # GPT-5.1-Codex-Max (OpenAI) - Max tokens: 128000, Context: 400000


  - model_name: gpt-4o
    litellm_params:
      model: github_copilot/gpt-4o
      extra_headers: *copilot_headers
    # GPT-4o (Azure OpenAI) - Max tokens: 4096, Context: 128000

  - model_name: gpt-4o-mini
    litellm_params:
      model: github_copilot/gpt-4o-mini
      extra_headers: *copilot_headers
    # GPT-4o mini (Azure OpenAI) - Max tokens: 4096, Context: 128000

  - model_name: gpt-4o-mini-2024-07-18
    litellm_params:
      model: github_copilot/gpt-4o-mini-2024-07-18
      extra_headers: *copilot_headers
    # GPT-4o mini (Azure OpenAI) - Max tokens: 4096, Context: 128000

  - model_name: gpt-4o-2024-11-20
    litellm_params:
      model: github_copilot/gpt-4o-2024-11-20
      extra_headers: *copilot_headers
    # GPT-4o (Azure OpenAI) - Max tokens: 16384, Context: 128000

  - model_name: gpt-4o-2024-08-06
    litellm_params:
      model: github_copilot/gpt-4o-2024-08-06
      extra_headers: *copilot_headers
    # GPT-4o (Azure OpenAI) - Max tokens: 16384, Context: 128000

  - model_name: gpt-4o-2024-05-13
    litellm_params:
      model: github_copilot/gpt-4o-2024-05-13
      extra_headers: *copilot_headers
    # GPT-4o (Azure OpenAI) - Max tokens: 4096, Context: 128000

  - model_name: gpt-4-o-preview
    litellm_params:
      model: github_copilot/gpt-4-o-preview
      extra_headers: *copilot_headers
    # GPT-4o Preview (Azure OpenAI) - Max tokens: 4096, Context: 128000

  - model_name: gpt-4
    litellm_params:
      model: github_copilot/gpt-4o 
      extra_headers: *copilot_headers
    # GPT-4 (routed to gpt-4o for tool support) - Max tokens: 4096, Context: 128000
  - model_name: gpt-4-1
    litellm_params:
      model: github_copilot/gpt-4.1
      extra_headers: *copilot_headers
    # GPT-4.1 (Azure OpenAI) - Max tokens: 16384, Context: 128000

  - model_name: gpt-4-1-2025-04-14
    litellm_params:
      model: github_copilot/gpt-4.1-2025-04-14
      extra_headers: *copilot_headers
    # GPT-4.1 (Azure OpenAI) - Max tokens: 16384, Context: 128000

  - model_name: gpt-4-0613
    litellm_params:
      model: github_copilot/gpt-4-0613
      extra_headers: *copilot_headers
    # GPT 4 (Azure OpenAI) - Max tokens: 4096, Context: 32768

  - model_name: gpt-3-5-turbo
    litellm_params:
      model: github_copilot/gpt-3.5-turbo
      extra_headers: *copilot_headers
    # GPT 3.5 Turbo (Azure OpenAI) - Max tokens: 4096, Context: 16384

  - model_name: gpt-3-5-turbo-0613
    litellm_params:
      model: github_copilot/gpt-3.5-turbo-0613
      extra_headers: *copilot_headers
    # GPT 3.5 Turbo (Azure OpenAI) - Max tokens: 4096, Context: 16384
  1. Start litellm with litellm --config copilot-config.yaml --port 4444
  2. Start claude, chat something like use the web search tool to read litellm doc
  3. Check the log output in claude code and litellm

Relevant log output

⏺ Web Search("JavaScript ES2026 new features")                                                   
  ⎿  Did 0 searches in 616ms



INFO:     127.0.0.1:49346 - "POST /v1/messages?beta=true HTTP/1.1" 200 OK
14:37:14 - LiteLLM Proxy:ERROR: endpoints.py:121 - litellm.proxy.proxy_server.anthropic_response(): Exception occured - litellm.BadRequestError: Github_copilotException - tools are required when tool choice is specified. Received Model Group=claude-haiku-4-5
Available Model Group Fallbacks=None
Traceback (most recent call last):
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/llms/openai/openai.py", line 1106, in async_streaming
    headers, response = await self.make_openai_chat_completion_request(
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<4 lines>...
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/litellm_core_utils/logging_utils.py", line 297, in async_wrapper
    result = await func(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/llms/openai/openai.py", line 460, in make_openai_chat_completion_request
    raise e
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/llms/openai/openai.py", line 437, in make_openai_chat_completion_request
    await openai_aclient.chat.completions.with_raw_response.create(
        **data, timeout=timeout
    )
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/openai/_legacy_response.py", line 384, in wrapped
    return cast(LegacyAPIResponse[R], await func(*args, **kwargs))
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/openai/resources/chat/completions/completions.py", line 2700, in create
    return await self._post(
           ^^^^^^^^^^^^^^^^^
    ...<49 lines>...
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/openai/_base_client.py", line 1884, in post
    return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/openai/_base_client.py", line 1669, in request
    raise self._make_status_error_from_response(err.response) from None
openai.BadRequestError: Error code: 400 - {'error': {'message': 'tools are required when tool choice is specified', 'code': 'invalid_request_body'}}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/main.py", line 613, in acompletion
    response = await init_response
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/llms/openai/openai.py", line 1156, in async_streaming
    raise OpenAIError(
    ...<4 lines>...
    )
litellm.llms.openai.common_utils.OpenAIError: Error code: 400 - {'error': {'message': 'tools are required when tool choice is specified', 'code': 'invalid_request_body'}}

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/proxy/anthropic_endpoints/endpoints.py", line 53, in anthropic_response
    result = await base_llm_response_processor.base_process_llm_request(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<16 lines>...
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/proxy/common_request_processing.py", line 886, in base_process_llm_request
    responses = await llm_responses
                ^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 4709, in async_wrapper
    return await self._ageneric_api_call_with_fallbacks(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 3458, in _ageneric_api_call_with_fallbacks
    raise e
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 3445, in _ageneric_api_call_with_fallbacks
    response = await self.async_function_with_fallbacks(**kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5111, in async_function_with_fallbacks
    return await self.async_function_with_fallbacks_common_utils(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<8 lines>...
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5068, in async_function_with_fallbacks_common_utils
    raise original_exception
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5102, in async_function_with_fallbacks
    response = await self.async_function_with_retries(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5257, in async_function_with_retries
    self.should_retry_this_error(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        error=e,
        ^^^^^^^^
    ...<4 lines>...
        content_policy_fallbacks=content_policy_fallbacks,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5439, in should_retry_this_error
    raise error
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5208, in async_function_with_retries
    response = await self.make_call(original_function, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 5354, in make_call
    response = await response
               ^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 3570, in _ageneric_api_call_with_fallbacks_helper
    raise e
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/router.py", line 3556, in _ageneric_api_call_with_fallbacks_helper
    response = await response  # type: ignore
               ^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/utils.py", line 2041, in wrapper_async
    raise e
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/utils.py", line 1862, in wrapper_async
    result = await original_function(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/llms/anthropic/experimental_pass_through/messages/handler.py", line 187, in anthropic_messages
    response = await init_response
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py", line 233, in async_anthropic_messages_handler
    completion_response = await litellm.acompletion(**completion_kwargs)
                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/utils.py", line 2041, in wrapper_async
    raise e
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/utils.py", line 1862, in wrapper_async
    result = await original_function(*args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/main.py", line 632, in acompletion
    raise exception_type(
          ~~~~~~~~~~~~~~^
        model=model,
        ^^^^^^^^^^^^
    ...<3 lines>...
        extra_kwargs=kwargs,
        ^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/litellm_core_utils/exception_mapping_utils.py", line 2398, in exception_type
    raise e
  File "/Users/JianGuo/claude-code-over-github-copilot/venv/lib/python3.14/site-packages/litellm/litellm_core_utils/exception_mapping_utils.py", line 507, in exception_type
    raise BadRequestError(
    ...<5 lines>...
    )
litellm.exceptions.BadRequestError: litellm.BadRequestError: Github_copilotException - tools are required when tool choice is specified. Received Model Group=claude-haiku-4-5
Available Model Group Fallbacks=None

What part of LiteLLM is this about?

Proxy

What LiteLLM version are you on ?

v1.82.0

Twitter / LinkedIn details

No response

extent analysis

TL;DR

The issue can be resolved by specifying the required tools when using the web search feature with LiteLLM.

Guidance

  • Verify that the tools parameter is included in the request when using the web search feature.
  • Check the LiteLLM documentation for the correct syntax and requirements for the tools parameter.
  • Ensure that the model being used supports the web search feature and that the necessary tools are configured correctly.
  • Review the error message and log output to identify the specific model and tool configuration that is causing the issue.

Example

No code example is provided as the issue is related to the configuration and usage of LiteLLM, rather than a specific code snippet.

Notes

The issue is specific to the LiteLLM proxy and the configuration of the web search feature. The error message indicates that tools are required when using the web search feature, but the tools are not specified in the request.

Recommendation

Apply a workaround by specifying the required tools when using the web search feature. This can be done by reviewing the LiteLLM documentation and configuring the tools parameter correctly. If the issue persists, consider upgrading to a later version of LiteLLM or seeking further support from the developers.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING