Skip to content

fix(bedrock): drop toolSpec.strict for Claude Sonnet 5 on Converse - #33196

Merged
tin-berri merged 1 commit into
BerriAI:litellm_oss_daily_2026_07_20from
kr0k:fix_bedrock_sonnet_5_strict_tools
Jul 30, 2026
Merged

fix(bedrock): drop toolSpec.strict for Claude Sonnet 5 on Converse#33196
tin-berri merged 1 commit into
BerriAI:litellm_oss_daily_2026_07_20from
kr0k:fix_bedrock_sonnet_5_strict_tools

Conversation

@kr0k

@kr0k kr0k commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes #33193

Linear ticket

Resolves LIT-4261

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Note on CI: after retargeting to litellm_oss_daily_2026_07_20 and rebasing, auth-and-jwt and Block fork dependency changes pass. The only red check is osv-scan, which flags two freshly published advisories in UI dev dependencies (brace-expansion, GHSA-3jxr-9vmj-r5cp and js-yaml, GHSA-52cp-r559-cp3m in ui/litellm-dashboard/package-lock.json); it fails the same way on sibling PRs #34083, #34067 and #34034, and fork PRs are not allowed to modify lockfiles per the Block fork dependency changes policy, so the bump has to happen in the canonical repository

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

The branch was later rebased onto litellm_oss_daily_2026_07_20 to satisfy the uv.lock parity check; the proof runs below were captured at the pre-rebase commits referenced in each section (10d5804b3e before, 2eee00e0f8 after) and the rebased head c2e887b2a2 carries the identical diff

Real Bedrock calls against us.anthropic.claude-sonnet-5 in us-east-1, proxy started with LITELLM_LOCAL_MODEL_COST_MAP=True so the local cost map (where this fix lives) is used instead of the remote one. Config:

model_list:
  - model_name: claude-sonnet
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-5
      aws_region_name: us-east-1

general_settings:
  master_key: sk-1234

Before, at base commit 10d5804b3e (litellm_oss_daily_2026_07_13). Tool definition contains strict and Bedrock rejects the request:

$ curl -sS http://localhost:4000/v1/chat/completions \
  -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet",
    "messages": [{"role": "user", "content": "what is the weather in Prague? use the tool"}],
    "max_tokens": 100,
    "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Get the weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}, "strict": true}}]
  }'

{"error":{"message":"litellm.BadRequestError: BedrockException - {\"message\":\"The model returned the following errors: tools.0.custom.strict: Extra inputs are not permitted\"}. Received Model Group=claude-sonnet\nAvailable Model Group Fallbacks=None","type":null,"param":null,"code":"400"}}

Before, same commit 10d5804b3e, /v1/responses with no strict anywhere in the request; the Responses to ChatCompletions bridge inserts the field itself, so this endpoint is broken for this model with no client-side workaround:

$ curl -sS http://localhost:4000/v1/responses \
  -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet",
    "input": "what is the weather in Prague? use the tool",
    "tools": [{"type": "function", "name": "get_weather", "description": "Get the weather for a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}]
  }'

{"error":{"message":"litellm.BadRequestError: BedrockException - {\"message\":\"The model returned the following errors: tools.0.custom.strict: Extra inputs are not permitted\"}. Received Model Group=claude-sonnet\nAvailable Model Group Fallbacks=None","type":null,"param":null,"code":"400"}}

After, at fix commit 2eee00e0f8, identical chat completions request now returns a real tool call:

{"id":"chatcmpl-8284e712-b85d-4ae0-b5d1-7528f6538703","created":1784022777,"model":"claude-sonnet","object":"chat.completion","choices":[{"finish_reason":"tool_calls","index":0,"message":{"content":"","role":"assistant","tool_calls":[{"index":0,"function":{"arguments":"{\"city\": \"Prague\"}","name":"get_weather"},"id":"tooluse_kUJAnoxDYhw0MVoHDlYqRT","type":"function"}]}}],"usage":{"completion_tokens":50,"prompt_tokens":444,"total_tokens":494,...}}

After, same commit 2eee00e0f8, identical /v1/responses request also succeeds; output contains the function call (response id and message item trimmed for brevity):

{"id":"resp_...","created_at":1784022840,"model":"claude-sonnet","object":"response","output":[{"type":"message",...},{"type":"function_call","name":"get_weather","arguments":"{\"city\": \"Prague\"}",...}],...}

Control checks from the same proxy: the chat completions request without the strict key succeeds on both commits, and strict is still forwarded for models that accept it (covered by the test_bedrock_tools_pt_strict_kept_for_other_anthropic cases)

Type

🐛 Bug Fix

Changes

Same shape as the #31582 fix for Opus 4.7/4.8. Bedrock routes Claude Sonnet 5 through the Anthropic-compatible validator that rejects toolSpec.strict, but the six Sonnet 5 entries (anthropic.claude-sonnet-5 plus global./us./eu./au./jp. inference profiles) never got the bedrock_converse_supports_strict_tools: false flag, so the gate in bedrock_converse_supports_strict_tools() fell back to its forward-by-default behavior for Anthropic models and every tool call carrying strict 400'd

This PR sets bedrock_converse_supports_strict_tools: false on those six entries in both model_prices_and_context_window.json and litellm/model_prices_and_context_window_backup.json, and extends the existing regression test file tests/test_litellm/litellm_core_utils/prompt_templates/test_bedrock_converse_strict_tools_opus_47_48.py with the Sonnet 5 cases (13 new parametrized cases across _bedrock_tools_pt, the bedrock_converse_supports_strict_tools helper and the cost map flag check). The new cases fail on the base commit and pass with the fix; the full file is 40 passed

@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a 400 error on Bedrock Converse when calling Claude Sonnet 5 with tools that include a strict field. Bedrock routes Sonnet 5 through a stricter Anthropic-compatible validator that rejects toolSpec.strict, but the six Sonnet 5 cost-map entries never had bedrock_converse_supports_strict_tools: false, so the gate function fell through to its default "forward" behavior for Anthropic models.

  • Adds bedrock_converse_supports_strict_tools: false to all six Sonnet 5 entries (anthropic.claude-sonnet-5 plus the global./us./eu./au./jp. inference profiles) in both model_prices_and_context_window.json and the backup file, exactly matching the pattern established for Opus 4.7/4.8 and Sonnet 4.
  • Extends the existing regression test suite with 13 new parametrized cases covering the _bedrock_tools_pt transformation, the bedrock_converse_supports_strict_tools helper, and the cost-map flag values; all tests are mock-only with no real network calls.

Confidence Score: 5/5

Safe to merge — the change is a pure data addition to the cost map that gates an existing code path, with no logic modifications and no backwards-incompatible behavior.

The fix adds a single boolean flag to six cost-map entries in both JSON files, exactly mirroring the pattern already in place for Opus 4.7/4.8 and Sonnet 4. The gate function and stripping logic in common_utils.py are untouched. New tests cover all six variants across three levels (tool transformation, helper function, and raw cost-map values), all without real network calls. PR description includes before/after real API proof. No existing tests are weakened or removed.

No files require special attention.

Important Files Changed

Filename Overview
model_prices_and_context_window.json Adds bedrock_converse_supports_strict_tools: false to all six Sonnet 5 entries, consistent with existing Opus 4.7/4.8 and Sonnet 4 entries.
litellm/model_prices_and_context_window_backup.json Mirror of the main JSON — same six Sonnet 5 entries receive bedrock_converse_supports_strict_tools: false, keeping both files in sync.
tests/test_litellm/litellm_core_utils/prompt_templates/test_bedrock_converse_strict_tools_opus_47_48.py Extends the existing regression suite with 13 new Sonnet 5 cases across three test functions; all tests are mock-only, covering the tool transformation, the helper function, and the cost-map flag values.

Reviews (1): Last reviewed commit: "fix(bedrock): drop toolSpec.strict for C..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@CLAassistant

CLAassistant commented Jul 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@kr0k
kr0k requested a review from a team July 16, 2026 19:01


def _classify_a2a_route(path: str) -> Optional[str]:
if path.endswith(_A2A_INVOKE_SUFFIX) and any(path.startswith(prefix) for prefix in _A2A_TRANSPORT_PREFIXES):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium: Bare A2A requests bypass metering

The A2A handler accepts message/send and message/stream through POST /a2a/{agent_id}, with the operation selected by the JSON-RPC method field. This classifier returns None for that path, so a customer can send successful billable agent requests through the bare route without incrementing the enterprise counter. Inspect the JSON-RPC method or have the endpoint stamp a server-controlled response marker so only billable operations on the multiplexed route are recorded.

@veria-ai

veria-ai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

PR overview

This PR adjusts Bedrock Converse handling for Claude Sonnet 5 by dropping the toolSpec.strict field from tool specifications. It also touches proxy middleware involved in classifying billable request metrics for agent traffic.

There is one open security issue: bare A2A JSON-RPC requests to message/send or message/stream can avoid enterprise metering when sent through the multiplexed /a2a/{agent_id} route. The impact is limited to billing and usage-accounting integrity rather than direct data access or code execution, but it is a confirmed customer-actionable bypass. No issues have been fixed or addressed yet.

Open issues (1)

Fixed/addressed: 0 · PR risk: 5/10

@kr0k
kr0k changed the base branch from litellm_oss_daily_2026_07_13 to litellm_oss_daily_2026_07_20 July 21, 2026 09:12
Bedrock routes Claude Sonnet 5 through the same Anthropic-compatible
validator as Opus 4.7/4.8 and Sonnet 4, which rejects toolSpec.strict
with 'tools.0.custom.strict: Extra inputs are not permitted'. Set
bedrock_converse_supports_strict_tools: false on all six Sonnet 5
entries so the existing gate strips the field, matching the fix shape
of BerriAI#31582
@icsy7867

Copy link
Copy Markdown

Waiting on this!

Will this work with inference profiles too?

I.E

      - model_name: claude-sonnet-5
        litellm_params:
          model: bedrock/converse/arn:aws-us-gov:bedrock:us-gov-east-1::foundation-model/anthropic.claude-sonnet-5
          model_id: arn:aws-us-gov:bedrock:us-gov-east-1:537798193888:application-inference-profile/xxxxxxxxxxxxxxxxxx

@tin-berri
tin-berri merged commit 7c56317 into BerriAI:litellm_oss_daily_2026_07_20 Jul 30, 2026
77 of 78 checks passed
@tin-berri

Copy link
Copy Markdown
Contributor

Waiting on this!

Will this work with inference profiles too?

I.E

      - model_name: claude-sonnet-5
        litellm_params:
          model: bedrock/converse/arn:aws-us-gov:bedrock:us-gov-east-1::foundation-model/anthropic.claude-sonnet-5
          model_id: arn:aws-us-gov:bedrock:us-gov-east-1:537798193888:application-inference-profile/xxxxxxxxxxxxxxxxxx

Yes this should work with that configuration as well

@kr0k

kr0k commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for merging, @tin-berri.

Flagging a follow-up so this doesn't get lost: the merge landed on
litellm_oss_daily_2026_07_20 (7c56317), and that branch hasn't made it back to
main — as of today main is 724 commits ahead of it, and the six
*anthropic.claude-sonnet-5 entries in model_prices_and_context_window.json
on main still carry no bedrock_converse_supports_strict_tools. Same for
v1.94.0, v1.95.0-rc.2 and v1.96.0-dev.2, so anyone hitting #33193 is still
getting the 400 (the cost map is fetched from main at startup, so a restart
or an image bump doesn't help yet).

The equivalent Opus 4.7/4.8 fix for #31582 reached main via #31923 with
litellm_internal_staging as the base, so I assume the same port is needed
here. Happy to open that PR against litellm_internal_staging myself if that's
the preferred route — just let me know, or cherry-pick 7c56317 if it's easier
on your side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants