Skip to content

chore(release): backport #30480 to stable/1.84.x and cut 1.84.9 - #30591

Merged
yuneng-berri merged 3 commits into
stable/1.84.xfrom
litellm_backport_1_84_x_bp_cachectrl_0616
Jun 17, 2026
Merged

chore(release): backport #30480 to stable/1.84.x and cut 1.84.9#30591
yuneng-berri merged 3 commits into
stable/1.84.xfrom
litellm_backport_1_84_x_bp_cachectrl_0616

Conversation

@yuneng-berri

Copy link
Copy Markdown
Collaborator

Relevant issues

Backports #30480 onto stable/1.84.x and cuts 1.84.9.

Anthropic and Bedrock Claude reject any request carrying more than 4 cache_control breakpoints with "A maximum of 4 blocks with cache_control may be provided." When a proxy model has cache_control_injection_points configured (for example role: system plus index: -1) and the client already sends cached system messages (Hermes-style), the AnthropicCacheControlHook was auto-injecting additional breakpoints without counting the client-supplied ones, pushing the total past 4 and turning otherwise valid requests into 400s. The fix caps auto-injection at the 4-breakpoint limit, counts client-supplied blocks toward it, skips messages that already carry cache_control so the client's TTL is preserved, reserves a slot when a tool_config injection point is present (the Bedrock transform appends a cachePoint), and stops once the limit is reached while honoring injection points in config order

The tip of stable/1.84.x (1.84.8) has shipped (tag v1.84.8, DockerHub image, and a published GitHub release all confirm it), so this backport bumps to 1.84.9

What is included

The pick is patch-identical to the staging commit (patch-id match; the only range-diff delta is the cherry-pick provenance footer), so there are no adaptation notes

Known noise on this line

None. The targeted test file passed cleanly at baseline before any pick (16 passed, 0 failed) once the proxy extra is installed so boto3 is available; the Bedrock-path tests fail only if that extra is missing, which is an environment artifact and not a code failure

Pre-Submission checklist

  • I have added meaningful tests
  • My PR's scope is as isolated as possible; it only solves 1 specific problem

Screenshots / Proof of Fix

Live proxy on stable/1.84.x (worktree at the branch tip) against the real Anthropic API, using a model configured with both cache_control_injection_points (role: system and index: -1). The reproducer sends 4 system messages that already carry client cache_control plus a user message; before the pick the hook injects a 5th breakpoint and Anthropic rejects it, after the pick the request is capped at 4 and succeeds

Reproducer payload (anthropic-cache-repro is anthropic/claude-haiku-4-5 with the two injection points configured):

{
  "model": "anthropic-cache-repro",
  "max_tokens": 50,
  "messages": [
    {"role":"system","content":[{"type":"text","text":"System block 0","cache_control":{"type":"ephemeral"}}]},
    {"role":"system","content":[{"type":"text","text":"System block 1","cache_control":{"type":"ephemeral"}}]},
    {"role":"system","content":[{"type":"text","text":"System block 2","cache_control":{"type":"ephemeral"}}]},
    {"role":"system","content":[{"type":"text","text":"System block 3","cache_control":{"type":"ephemeral"}}]},
    {"role":"user","content":"hello"}
  ]
}

Before the pick (baseline on stable/1.84.x tip):

$ curl -s -w "\nHTTP_STATUS:%{http_code}\n" http://localhost:4001/v1/chat/completions \
    -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" --data @repro_payload.json
{"error":{"message":"litellm.BadRequestError: AnthropicException - {\"type\":\"error\",\"error\":{\"type\":\"invalid_request_error\",\"message\":\"A maximum of 4 blocks with cache_control may be provided. Found 5.\"},...}
HTTP_STATUS:400

After the pick (same request, same line, fix applied):

$ curl -s -w "\nHTTP_STATUS:%{http_code}\n" http://localhost:4001/v1/chat/completions \
    -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" --data @repro_payload.json
HTTP 200 | SUCCESS | content: "# Hello! How can I help you today? ..."
usage: {"prompt_tokens":24,"completion_tokens":40,"total_tokens":64,...}

Sanity (both before and after): proxy health returns alive, a DB-backed virtual key generates, and a plain anthropic-plain completion returns a real response

Targeted test delta on stable/1.84.x: 16 passed at baseline, 22 passed after the pick (the 6 regression tests the PR adds all pass on this line), 0 new failures

Gauntlet (behavioral, universal): SURVIVED on all three sub-claims; every identifier the pick introduces resolves on this tree, the 6 new regression tests plus the 16 pre-existing ones pass (22/22), and no existing caller of AnthropicCacheControlHook breaks (the rename of _process_message_injection into the new helpers leaves no orphaned callers). The adversarial edge investigator could not construct a single input that exceeds the 4-block cap

Type

🐛 Bug Fix

Changes

Cherry-pick of #30480 onto stable/1.84.x with a patch version bump to 1.84.9 and a lock refresh

shivamrawat1 and others added 3 commits June 16, 2026 17:54
…30480)

* fix(integrations): cap Anthropic cache_control injection at 4 blocks

Respect Anthropic's 4 cache_control breakpoint limit by counting client-supplied blocks, skipping messages that already carry cache_control, and stopping further auto-injection once the limit is reached.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(integrations): reserve cache slot for tool_config and short-circuit cap

Address review feedback on the cache_control cap: break out of the injection loop before resolving target indices once the limit is reached, and reserve one of the four breakpoint slots when a tool_config injection point is present so the cachePoint appended by the Bedrock transform does not push the total past Anthropic's limit.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit fc9d789)
@yuneng-berri
yuneng-berri requested a review from a team June 17, 2026 01:14
@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Cherry-picks staging commit fc9d789 onto stable/1.84.x to fix AnthropicCacheControlHook over-injecting cache_control breakpoints past Anthropic's hard limit of 4, then bumps the version to 1.84.9.

  • Refactors message-injection into _apply_message_injections + _resolve_target_indices; counts client-supplied breakpoints upfront, skips messages that already carry cache_control (preserving client TTL), stops injection once the 4-block cap is reached, and reserves one slot when a tool_config injection point is configured.
  • Adds 6 mock-only regression tests covering the cap, TTL preservation, tool_config slot reservation, and end-to-end Bedrock payload shape.

Confidence Score: 4/5

The backport is a clean patch-identical cherry-pick with six focused regression tests; the only rough edge is a log message that reports the wrong block limit when a tool_config reservation reduces the cap from 4 to 3.

The hook's cap-and-count logic is correct, the client-TTL-preservation behavior is tested end-to-end, and no existing callers are broken. A minor logging inaccuracy in the warning message is the sole finding — the number printed is always 4 even when the effective injection limit is 3 due to the tool_config slot reservation.

anthropic_cache_control_hook.py — specifically the warning message in _apply_message_injections that references MAX_CACHE_CONTROL_BLOCKS instead of the actual max_blocks argument.

Important Files Changed

Filename Overview
litellm/integrations/anthropic_cache_control_hook.py Core fix: adds MAX_CACHE_CONTROL_BLOCKS constant, counts client-supplied breakpoints before injecting, skips already-tagged messages, caps injection at 4, and reserves a slot for tool_config points. One minor logging inaccuracy (warning always prints 4 even when effective limit is 3 due to reservation).
tests/test_litellm/integrations/test_anthropic_cache_control_hook.py Adds 6 regression tests covering the cap, client-TTL preservation, tool_config reservation, and end-to-end Bedrock payload shape; all use mocks, no real network calls.
pyproject.toml Version bump from 1.84.8 to 1.84.9 in both [project] and [tool.commitizen] sections.

Reviews (1): Last reviewed commit: "chore: refresh uv.lock for 1.84.9" | Re-trigger Greptile

@mateo-berri mateo-berri left a comment

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.

LGTM; thanks!

Comment on lines +152 to +156
if limit_reached:
verbose_logger.warning(
f"AnthropicCacheControlHook: Reached the Anthropic limit of "
f"{MAX_CACHE_CONTROL_BLOCKS} cache_control blocks. Skipping further injection."
)

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.

P2 The warning always prints MAX_CACHE_CONTROL_BLOCKS (4) even when the effective cap passed to this method is 3 (because a tool_config reservation reduced max_blocks). In that scenario the log says "Reached the Anthropic limit of 4" while the actual stop was at 3, which will confuse anyone debugging a tool_config-capped request.

Suggested change
if limit_reached:
verbose_logger.warning(
f"AnthropicCacheControlHook: Reached the Anthropic limit of "
f"{MAX_CACHE_CONTROL_BLOCKS} cache_control blocks. Skipping further injection."
)
if limit_reached:
verbose_logger.warning(
f"AnthropicCacheControlHook: Reached the injection limit of "
f"{max_blocks} cache_control blocks. Skipping further injection."
)

@yuneng-berri
yuneng-berri merged commit b860b2f into stable/1.84.x Jun 17, 2026
40 of 62 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_backport_1_84_x_bp_cachectrl_0616 branch June 17, 2026 01:20
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.

3 participants