litellm - ✅(Solved) Fix fix(vertex_ai): strip scope from cache_control for Anthropic messages passthrough [1 pull requests, 1 comments, 2 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#23149Fetched 2026-04-08 00:38:23
View on GitHub
Comments
1
Participants
2
Timeline
7
Reactions
2
Author
Timeline (top)
cross-referenced ×2labeled ×2closed ×1commented ×1

Error Message

Actual: 400 error cache_control.ephemeral.scope: Extra inputs are not permitted

Root Cause

In PR #22867, _remove_scope_from_cache_control was added for Bedrock and Azure AI, but Vertex AI was missed.

  • litellm/llms/azure_ai/anthropic/messages_transformation.py — has _remove_scope_from_cache_control
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py — has cache_control.pop("scope", None)
  • litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.pymissing

Fix Action

Fixed

PR fix notes

PR #23183: PR #22867 added _remove_scope_from_cache_control for Bedrock and Azur…

Description (problem / solution / changelog)

…e AI but omitted Vertex AI. This applies the same pattern to VertexAIPartnerModelsAnthropicMessagesConfig."

Relevant issues

Fixes https://github.com/BerriAI/litellm/issues/23149

Pre-Submission checklist

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

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

CI (LiteLLM team)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Type

<!-- Select the type of Pull Request --> <!-- Keep only the necessary ones -->

🆕 New Feature 🐛 Bug Fix 🧹 Refactoring 📖 Documentation 🚄 Infrastructure ✅ Test

Changes

Changed files

  • litellm/llms/anthropic/experimental_pass_through/messages/transformation.py (modified, +32/-0)
  • litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py (modified, +2/-0)
  • tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py (modified, +45/-0)

Code Example

system.1.cache_control.ephemeral.scope: Extra inputs are not permitted

---

curl http://localhost:4000/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: <key>" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: prompt-caching-scope-2026-01-05" \
  -d '{
    "model": "claude-opus-4-6",
    "max_tokens": 100,
    "system": [
      {"type": "text", "text": "You are helpful"},
      {"type": "text", "text": "Be concise", "cache_control": {"type": "ephemeral", "scope": "turn"}}
    ],
    "messages": [{"role": "user", "content": "hi"}]
  }'

---

def _remove_scope_from_cache_control(self, anthropic_messages_request: Dict) -> None:
    def _sanitize(cache_control):
        if isinstance(cache_control, dict):
            cache_control.pop("scope", None)

    def _process_content_list(content):
        for item in content:
            if isinstance(item, dict) and "cache_control" in item:
                _sanitize(item["cache_control"])

    if "system" in anthropic_messages_request:
        system = anthropic_messages_request["system"]
        if isinstance(system, list):
            _process_content_list(system)

    if "messages" in anthropic_messages_request:
        for message in anthropic_messages_request["messages"]:
            if isinstance(message, dict) and "content" in message:
                content = message["content"]
                if isinstance(content, list):
                    _process_content_list(content)
RAW_BUFFERClick to expand / collapse

Bug Description

When Claude Code (or any client) sends cache_control with scope field via the Anthropic Messages passthrough endpoint (/v1/messages) to Vertex AI, the request fails with:

system.1.cache_control.ephemeral.scope: Extra inputs are not permitted

Vertex AI does not support the scope field in cache_control (the prompt-caching-scope-2026-01-05 beta). LiteLLM already correctly filters out the prompt-caching-scope-2026-01-05 beta header for Vertex AI in anthropic_beta_headers_config.json (set to null), but does not strip the scope field from the request body.

Root Cause

In PR #22867, _remove_scope_from_cache_control was added for Bedrock and Azure AI, but Vertex AI was missed.

  • litellm/llms/azure_ai/anthropic/messages_transformation.py — has _remove_scope_from_cache_control
  • litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py — has cache_control.pop("scope", None)
  • litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.pymissing

Steps to Reproduce

  1. Configure LiteLLM with a Vertex AI Claude model
  2. Send a request to /v1/messages with cache_control containing scope:
curl http://localhost:4000/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: <key>" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: prompt-caching-scope-2026-01-05" \
  -d '{
    "model": "claude-opus-4-6",
    "max_tokens": 100,
    "system": [
      {"type": "text", "text": "You are helpful"},
      {"type": "text", "text": "Be concise", "cache_control": {"type": "ephemeral", "scope": "turn"}}
    ],
    "messages": [{"role": "user", "content": "hi"}]
  }'

Expected: scope stripped from body, request succeeds
Actual: 400 error cache_control.ephemeral.scope: Extra inputs are not permitted

Suggested Fix

Add _remove_scope_from_cache_control to VertexAIPartnerModelsAnthropicMessagesConfig in litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py, matching the Azure AI implementation:

def _remove_scope_from_cache_control(self, anthropic_messages_request: Dict) -> None:
    def _sanitize(cache_control):
        if isinstance(cache_control, dict):
            cache_control.pop("scope", None)

    def _process_content_list(content):
        for item in content:
            if isinstance(item, dict) and "cache_control" in item:
                _sanitize(item["cache_control"])

    if "system" in anthropic_messages_request:
        system = anthropic_messages_request["system"]
        if isinstance(system, list):
            _process_content_list(system)

    if "messages" in anthropic_messages_request:
        for message in anthropic_messages_request["messages"]:
            if isinstance(message, dict) and "content" in message:
                content = message["content"]
                if isinstance(content, list):
                    _process_content_list(content)

Then call self._remove_scope_from_cache_control(anthropic_messages_request) in transform_anthropic_messages_request().

Related

  • PR #22867 — fix for Bedrock and Azure AI (Vertex AI was missed)
  • PR #20058 — filtered prompt-caching-scope-2026-01-05 header for Vertex AI
  • Issue #19984 — original beta header issue

Environment

  • LiteLLM version: v1.81.14-stable (also reproducible on latest main)
  • Provider: vertex_ai
  • Client: Claude Code

extent analysis

Fix Plan

To fix the issue, you need to add the _remove_scope_from_cache_control method to the VertexAIPartnerModelsAnthropicMessagesConfig class in litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py. This method will remove the scope field from the cache_control dictionary in the request body.

Here are the steps:

  • Add the _remove_scope_from_cache_control method:
def _remove_scope_from_cache_control(self, anthropic_messages_request: Dict) -> None:
    def _sanitize(cache_control):
        if isinstance(cache_control, dict):
            cache_control.pop("scope", None)

    def _process_content_list(content):
        for item in content:
            if isinstance(item, dict) and "cache_control" in item:
                _sanitize(item["cache_control"])

    if "system" in anthropic_messages_request:
        system = anthropic_messages_request["system"]
        if isinstance(system, list):
            _process_content_list(system)

    if "messages" in anthropic_messages_request:
        for message in anthropic_messages_request["messages"]:
            if isinstance(message, dict) and "content" in message:
                content = message["content"]
                if isinstance(content, list):
                    _process_content_list(content)
  • Call self._remove_scope_from_cache_control(anthropic_messages_request) in the transform_anthropic_messages_request() method:
def transform_anthropic_messages_request(self, anthropic_messages_request: Dict) -> Dict:
    self._remove_scope_from_cache_control(anthropic_messages_request)
    # rest of the method implementation

Verification

To verify that the fix worked, you can send a request to /v1/messages with cache_control containing scope and check that the request succeeds:

curl http://localhost:4000/v1/messages \
  -H "Content-Type: application/json" \
  -H "x-api-key: <key>" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: prompt-caching-scope-2026-01-05" \
  -d '{
    "model": "claude-opus-4-6",
    "max_tokens": 100,
    "system": [
      {"type": "text", "text": "You are helpful"},
      {"type": "text", "text": "Be concise", "cache_control": {"type": "ephemeral", "scope": "turn"}}
    ],
    "messages": [{"role": "user", "content": "hi"}]
  }'

The request should succeed without returning a 400 error.

Extra Tips

Make sure to test the fix thoroughly to ensure that it does not introduce any regressions

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