litellm - ✅(Solved) Fix [Bug]: KeyError: 'name' in translate_anthropic_tools_to_openai when guardrails process Anthropic built-in tools (bash, text_editor, computer) [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#23461Fetched 2026-04-08 00:44:07
View on GitHub
Comments
0
Participants
1
Timeline
9
Reactions
3
Author
Participants
Timeline (top)
referenced ×4labeled ×2subscribed ×2cross-referenced ×1

Error Message

File "/usr/lib/python3.13/site-packages/litellm/proxy/anthropic_endpoints/endpoints.py", line 53, in anthropic_response result = await base_llm_response_processor.base_process_llm_request(...) File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 807, in base_process_llm_request self.data, logging_obj = await self.common_processing_pre_call_logic(...) File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 667, in common_processing_pre_call_logic self.data = await proxy_logging_obj.pre_call_hook(...) File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1400, in pre_call_hook raise e File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1349, in pre_call_hook result = await self._process_guardrail_callback(...) File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1017, in _process_guardrail_callback response = await self._execute_guardrail_hook(...) File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 892, in _execute_guardrail_hook return await target.async_pre_call_hook(...) File "/usr/lib/python3.13/site-packages/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py", line 124, in async_pre_call_hook data = await endpoint_translation.process_input_messages(...) File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/chat/guardrail_translation/handler.py", line 79, in process_input_messages LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai( anthropic_message_request=cast(AnthropicMessagesRequest, data.copy()) ) File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py", line 910, in translate_anthropic_to_openai new_kwargs["tools"], tool_name_mapping = self.translate_anthropic_tools_to_openai( tools=cast(List[AllAnthropicToolsValues], regular_tools), model=new_kwargs.get("model"), ) File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py", line 736, in translate_anthropic_tools_to_openai original_name = tool["name"] ~~~~^^^^^^^^ KeyError: 'name'

Root Cause

Note: This does NOT happen on /v1/chat/completions (OpenAI format) — only on the Anthropic pass-through endpoint, because only that path receives native Anthropic tool types.

Fix Action

Fixed

PR fix notes

PR #23473: fix(anthropic): skip built-in tools in translate_anthropic_tools_to_openai

Description (problem / solution / changelog)

Summary

Fixes #23461

Anthropic built-in tools (bash_20250124, text_editor_20250124, computer_20250124) only have a type field — no name. When guardrails process requests containing these tools via translate_anthropic_to_openai, the translation crashes with KeyError: 'name' at line 775 of transformation.py.

Root cause: The tool filtering at line 939-943 only separates web search tools. Built-in tools pass _is_web_search_tool and land in regular_tools, which are then passed to translate_anthropic_tools_to_openai where tool["name"] is unconditionally accessed.

Fix: Skip tools without a name key in translate_anthropic_tools_to_openai. These are Anthropic-native tools with no OpenAI equivalent — they should be passed through to the backend untranslated.

Changes

  • litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py — 2-line guard: if "name" not in tool: continue
  • Added 2 regression tests: unit-level (translate_anthropic_tools_to_openai with mixed built-in + regular tools) and end-to-end (translate_anthropic_to_openai full request)

Test plan

  • test_translate_anthropic_tools_to_openai_skips_builtin_tools — verifies built-in tools are skipped, regular tools translate correctly
  • test_translate_anthropic_to_openai_with_builtin_and_regular_tools — end-to-end with AnthropicMessagesRequest
  • All existing tests pass (no regressions)

Made with Cursor

Changed files

  • litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py (modified, +7/-4)
  • tests/test_litellm/llms/anthropic/experimental_pass_through/adapters/test_anthropic_experimental_pass_through_adapters_transformation.py (modified, +148/-0)

Code Example

// Regular Anthropic tool (has "name") ✅
{"name": "my_tool", "description": "...", "input_schema": {...}}

// Anthropic built-in tools (NO "name") ❌
{"type": "bash_20250124"}
{"type": "text_editor_20250124"}
{"type": "computer_20250124", "display_width_px": 1024, "display_height_px": 768}

---

def translate_anthropic_tools_to_openai(
    self, tools: List[AllAnthropicToolsValues], model: Optional[str] = None
) -> Tuple[List[ChatCompletionToolParam], Dict[str, str]]:
    new_tools: List[ChatCompletionToolParam] = []
    tool_name_mapping: Dict[str, str] = {}
    mapped_tool_params = ["name", "input_schema", "description", "cache_control"]
    for tool in tools:
        original_name = tool["name"]  # 💥 KeyError here for built-in tools
        # ...

---

for tool in tools:
    if "name" not in tool:
        # Built-in Anthropic tool type (bash, text_editor, computer) — skip translation
        continue
    original_name = tool["name"]
    # ...

---

guardrails:
  - guardrail_name: gdpr-eu-business-identifiers
    litellm_params:
      guardrail: litellm_content_filter
      default_on: true

---

curl -X POST https://your-proxy/anthropic/v1/messages \
  -H "x-api-key: sk-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4.6",
    "max_tokens": 4096,
    "tools": [
      {"type": "bash_20250124"},
      {"type": "text_editor_20250124"},
      {"name": "regular_tool", "description": "A normal tool", "input_schema": {"type": "object"}}
    ],
    "messages": [{"role": "user", "content": "Hello"}]
  }'

---

File "/usr/lib/python3.13/site-packages/litellm/proxy/anthropic_endpoints/endpoints.py", line 53, in anthropic_response
    result = await base_llm_response_processor.base_process_llm_request(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 807, in base_process_llm_request
    self.data, logging_obj = await self.common_processing_pre_call_logic(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 667, in common_processing_pre_call_logic
    self.data = await proxy_logging_obj.pre_call_hook(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1400, in pre_call_hook
    raise e
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1349, in pre_call_hook
    result = await self._process_guardrail_callback(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1017, in _process_guardrail_callback
    response = await self._execute_guardrail_hook(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 892, in _execute_guardrail_hook
    return await target.async_pre_call_hook(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py", line 124, in async_pre_call_hook
    data = await endpoint_translation.process_input_messages(...)
File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/chat/guardrail_translation/handler.py", line 79, in process_input_messages
    LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(
        anthropic_message_request=cast(AnthropicMessagesRequest, data.copy())
    )
File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py", line 910, in translate_anthropic_to_openai
    new_kwargs["tools"], tool_name_mapping = self.translate_anthropic_tools_to_openai(
        tools=cast(List[AllAnthropicToolsValues], regular_tools),
        model=new_kwargs.get("model"),
    )
File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py", line 736, in translate_anthropic_tools_to_openai
    original_name = tool["name"]
                    ~~~~^^^^^^^^
KeyError: 'name'
RAW_BUFFERClick to expand / collapse

Disclaimer:

  • Bug filed with assistance of Claude-Opus-4.6

What happened?

When using Claude Code (or any client that sends Anthropic built-in tool types like bash_20250124, text_editor_20250124, computer_20250124) through the Anthropic pass-through endpoint (/anthropic/v1/messages), the request crashes with a KeyError: 'name' during guardrail pre-call processing.

The crash occurs in translate_anthropic_tools_to_openai() at line 736 of litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py. This function assumes every tool has a "name" field, but Anthropic's built-in tool types only have a "type" field — no "name":

// Regular Anthropic tool (has "name") ✅
{"name": "my_tool", "description": "...", "input_schema": {...}}

// Anthropic built-in tools (NO "name") ❌
{"type": "bash_20250124"}
{"type": "text_editor_20250124"}
{"type": "computer_20250124", "display_width_px": 1024, "display_height_px": 768}

The buggy code (line 736):

def translate_anthropic_tools_to_openai(
    self, tools: List[AllAnthropicToolsValues], model: Optional[str] = None
) -> Tuple[List[ChatCompletionToolParam], Dict[str, str]]:
    new_tools: List[ChatCompletionToolParam] = []
    tool_name_mapping: Dict[str, str] = {}
    mapped_tool_params = ["name", "input_schema", "description", "cache_control"]
    for tool in tools:
        original_name = tool["name"]  # 💥 KeyError here for built-in tools
        # ...

The fix should skip or handle built-in tool types that don't have a "name" field. For example:

for tool in tools:
    if "name" not in tool:
        # Built-in Anthropic tool type (bash, text_editor, computer) — skip translation
        continue
    original_name = tool["name"]
    # ...

Steps to Reproduce

  1. Configure LiteLLM proxy with any guardrail enabled (e.g., litellm_content_filter for GDPR):
guardrails:
  - guardrail_name: gdpr-eu-business-identifiers
    litellm_params:
      guardrail: litellm_content_filter
      default_on: true
  1. Send a request via the Anthropic pass-through endpoint (/anthropic/v1/messages) with built-in tool types:
curl -X POST https://your-proxy/anthropic/v1/messages \
  -H "x-api-key: sk-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4.6",
    "max_tokens": 4096,
    "tools": [
      {"type": "bash_20250124"},
      {"type": "text_editor_20250124"},
      {"name": "regular_tool", "description": "A normal tool", "input_schema": {"type": "object"}}
    ],
    "messages": [{"role": "user", "content": "Hello"}]
  }'
  1. Observe the KeyError: 'name' crash.

Note: This does NOT happen on /v1/chat/completions (OpenAI format) — only on the Anthropic pass-through endpoint, because only that path receives native Anthropic tool types.

Relevant log output

File "/usr/lib/python3.13/site-packages/litellm/proxy/anthropic_endpoints/endpoints.py", line 53, in anthropic_response
    result = await base_llm_response_processor.base_process_llm_request(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 807, in base_process_llm_request
    self.data, logging_obj = await self.common_processing_pre_call_logic(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/common_request_processing.py", line 667, in common_processing_pre_call_logic
    self.data = await proxy_logging_obj.pre_call_hook(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1400, in pre_call_hook
    raise e
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1349, in pre_call_hook
    result = await self._process_guardrail_callback(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 1017, in _process_guardrail_callback
    response = await self._execute_guardrail_hook(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/utils.py", line 892, in _execute_guardrail_hook
    return await target.async_pre_call_hook(...)
File "/usr/lib/python3.13/site-packages/litellm/proxy/guardrails/guardrail_hooks/unified_guardrail/unified_guardrail.py", line 124, in async_pre_call_hook
    data = await endpoint_translation.process_input_messages(...)
File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/chat/guardrail_translation/handler.py", line 79, in process_input_messages
    LiteLLMAnthropicMessagesAdapter().translate_anthropic_to_openai(
        anthropic_message_request=cast(AnthropicMessagesRequest, data.copy())
    )
File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py", line 910, in translate_anthropic_to_openai
    new_kwargs["tools"], tool_name_mapping = self.translate_anthropic_tools_to_openai(
        tools=cast(List[AllAnthropicToolsValues], regular_tools),
        model=new_kwargs.get("model"),
    )
File "/usr/lib/python3.13/site-packages/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py", line 736, in translate_anthropic_tools_to_openai
    original_name = tool["name"]
                    ~~~~^^^^^^^^
KeyError: 'name'

Related issues

  • #22821 — Presidio guardrail broken with Anthropic native API (same area: guardrail tool translation on pass-through endpoint)
  • #6427 — Feature request for supporting Anthropic built-in tool types (computer_use, bash, text_editor)

Additional context

  • Client: Claude Code (uses /anthropic/v1/messages with built-in tools)
  • LiteLLM version: v1.81.14
  • Guardrails: Any guardrail that triggers the unified_guardrailprocess_input_messagestranslate_anthropic_to_openai path
  • Component: Proxy

extent analysis

Fix Plan

To fix the KeyError: 'name' issue, we need to modify the translate_anthropic_tools_to_openai function to handle Anthropic built-in tool types that don't have a "name" field.

Here are the steps:

  • Modify the translate_anthropic_tools_to_openai function to check if the "name" field exists in the tool before trying to access it.
  • If the "name" field does not exist, skip the translation for that tool.

Code Changes

def translate_anthropic_tools_to_openai(
    self, tools: List[AllAnthropicToolsValues], model: Optional[str] = None
) -> Tuple[List[ChatCompletionToolParam], Dict[str, str]]:
    new_tools: List[ChatCompletionToolParam] = []
    tool_name_mapping: Dict[str, str] = {}
    mapped_tool_params = ["name", "input_schema", "description", "cache_control"]
    for tool in tools:
        if "name" not in tool:
            # Built-in Anthropic tool type (bash, text_editor, computer) — skip translation
            continue
        original_name = tool["name"]
        #... rest of the function remains the same

Alternatively, you can also use the .get() method to provide a default value if the "name" field does not exist:

original_name = tool.get("name")
if original_name is None:
    # Built-in Anthropic tool type (bash, text_editor, computer) — skip translation
    continue

Verification

To verify that the fix worked, you can send a request via the Anthropic pass-through endpoint (/anthropic/v1/messages) with built-in tool types and check that the KeyError: 'name' crash no longer occurs.

Extra Tips

  • Make sure to test the fix with different types of tools, including built-in Anthropic tool types and regular tools with a "name" field.
  • Consider adding a log message or a warning when a built-in Anthropic tool type is skipped to help with debugging and monitoring.

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

litellm - ✅(Solved) Fix [Bug]: KeyError: 'name' in translate_anthropic_tools_to_openai when guardrails process Anthropic built-in tools (bash, text_editor, computer) [1 pull requests, 1 participants]