litellm - ✅(Solved) Fix [Bug]: remove_custom_field_from_tools() strips defer_loading — breaks Tool Search on Bedrock, wastes ~20k tokens per request [1 pull requests]

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…

Root Cause

remove_custom_field_from_tools() in litellm/llms/bedrock/common_utils.py unconditionally removes the custom field:

  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py
  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py

Fix Action

Fixed

PR fix notes

PR #26143: fix(bedrock): remove remove_custom_field_from_tools — Bedrock now supports custom.defer_loading natively

Description (problem / solution / changelog)

Summary

Removes remove_custom_field_from_tools() and all its call sites.

This function was added in #22861 (fixing #22847) to strip the custom: {defer_loading: true} field from tool definitions before forwarding to Bedrock, because Bedrock was rejecting it with "Extra inputs are not permitted".

Bedrock has since been updated and now accepts custom.defer_loading natively. When using Claude Code directly against Bedrock (without LiteLLM), Tool Search works correctly. But routing through LiteLLM → Bedrock caused the field to be stripped, defeating the feature and loading every tool definition into context — adding ~20k+ extra input tokens per request for a typical MCP setup.

Changes

  • litellm/llms/bedrock/common_utils.py: Remove remove_custom_field_from_tools() function
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py: Remove import + call
  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py: Remove import + call
  • tests/…/test_anthropic_claude3_transformation.py: Remove test_remove_custom_field_from_tools test

Note: normalize_json_schema_custom_types_to_object() and normalize_tool_input_schema_types_for_bedrock_invoke() are intentionally kept — they handle type: "custom" in JSON schemas, which is a separate issue that Bedrock still does not accept.

Test plan

  • Verify existing Bedrock invoke tests pass
  • Manually test with Claude Code + LiteLLM → Bedrock: confirm defer_loading is preserved in tool definitions
  • Confirm token usage drops to match direct Bedrock path

Fixes #26113

🤖 Generated with Claude Code

Changed files

  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py (modified, +0/-3)
  • litellm/llms/bedrock/common_utils.py (modified, +0/-21)
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py (modified, +0/-6)
  • tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py (modified, +0/-55)
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?

PR #22861 (merged 2026-03-05, fixing #22847) added remove_custom_field_from_tools() to strip the custom: {defer_loading: true} field from tool definitions before forwarding to Bedrock. At the time, Bedrock rejected this field with Extra inputs are not permitted.

Bedrock has since updated and now accepts custom.defer_loading. When using Claude Code directly against Bedrock (without LiteLLM), Tool Search works correctly — deferred MCP tools are excluded from the system prompt prefix and only ~1.2% of context is consumed by MCP tool definitions.

However, when routing through LiteLLM → Bedrock, remove_custom_field_from_tools() unconditionally strips the custom field. Bedrock then sees all tools as non-deferred and loads every tool definition into the context. This causes ~20k+ extra input tokens per request for a typical MCP setup (22 tools across 5 MCP servers).

Impact

PathMCP tools token costBehavior
Claude Code → Bedrock (direct)~12k tokens (1.2% of context)defer_loading preserved, Tool Search works
Claude Code → LiteLLM → Bedrock~30k+ tokensdefer_loading stripped, all tools fully loaded

This is not just a logging/display issue — it's real additional token consumption and cost on every request.

Root cause

remove_custom_field_from_tools() in litellm/llms/bedrock/common_utils.py unconditionally removes the custom field:

  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py
  • litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py

Suggested fix

Remove remove_custom_field_from_tools() entirely, or make it conditional/configurable. Bedrock now accepts this field natively.

Steps to Reproduce

  1. Configure Claude Code to use LiteLLM proxy pointing to Bedrock
  2. Add multiple MCP servers (e.g., exa, aws-knowledge, aws-pricing, context7, calculator — 22 tools total)
  3. Start a conversation with a simple prompt like "hi"
  4. Compare token usage in LiteLLM logs vs direct Bedrock connection
  5. LiteLLM path shows ~30k+ tokens for messages; direct Bedrock shows ~2.5k

Environment

  • LiteLLM: v1.82.3-stable (Production)
  • Claude Code: latest
  • Bedrock region: ap-northeast-1
  • Model: Claude Opus 4.6 / Sonnet 4.6

Relevant log output

In LiteLLM request logs, the forwarded request to Bedrock contains tool definitions without custom.defer_loading, while the original request from Claude Code includes it.

Are you a LiteLLM Enterprise user?

No

Twitter / LinkedIn details

No response

extent analysis

TL;DR

Remove or modify the remove_custom_field_from_tools() function to conditionally preserve the custom field, allowing Bedrock to accept custom.defer_loading and reduce token consumption.

Guidance

  • Identify the remove_custom_field_from_tools() function in litellm/llms/bedrock/common_utils.py and consider removing it or making it conditional to preserve the custom field.
  • Verify the change by checking the LiteLLM logs for the presence of custom.defer_loading in the forwarded request to Bedrock.
  • Test the updated configuration with multiple MCP servers and compare token usage between the LiteLLM and direct Bedrock connections.
  • Consider configuring the remove_custom_field_from_tools() function to be conditional based on the Bedrock version or configuration, to ensure compatibility with future updates.

Example

No code snippet is provided as the issue does not require a specific code change, but rather a modification to the existing remove_custom_field_from_tools() function.

Notes

The suggested fix assumes that the remove_custom_field_from_tools() function is the primary cause of the issue, and that modifying or removing it will resolve the token consumption problem. However, additional testing and verification may be necessary to ensure the change does not introduce other issues.

Recommendation

Apply workaround: Modify the remove_custom_field_from_tools() function to conditionally preserve the custom field, as Bedrock now accepts custom.defer_loading and this change should reduce token consumption.

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