[BUG] CLAUDE_CODE_USE_BEDROCK=1 writes <2% of prompt to cache at >150k context, vs full prompt on Anthropic 1P direct

Resolved 💬 3 comments Opened May 20, 2026 by bse-ai Closed Jun 29, 2026

Preflight

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (v2.1.144)

What's Wrong?

When CLAUDE_CODE_USE_BEDROCK=1 is set and the user prompt is large (>150k tokens), Claude Code emits a cache_control marker that covers only a tiny fraction of the prompt. The same prompt sent through Claude Code in default mode (Anthropic 1P direct) caches the full prompt correctly.

Concretely, with a single ~350k-token user-content prompt:

| Mode | cache_creation_input_tokens | TTFT cold | TTFT warm |
|---|---|---|---|
| CC + Anthropic 1P direct | ~790,000 (full prompt) | ~12s | ~5s |
| CC + Bedrock direct (CLAUDE_CODE_USE_BEDROCK=1) | ~6,500 (≈1.7% of prompt) | ~33-75s | ~33-45s (no warm-up) |

Same Claude Code version (v2.1.144), same model (claude-sonnet-4-6), same prompt fixture, run minutes apart. The Bedrock-mode path effectively never warms because almost nothing gets written to the cache.

This is not a Bedrock-side limit — see "Control test" below; Bedrock honors a single cache_control: {"type": "ephemeral"} marker at 300k context and caches the full ~393k tokens correctly when the request body has the marker placed on the user content.

What Should Happen?

CLAUDE_CODE_USE_BEDROCK=1 mode should place cache_control markers such that the bulk of the user prompt is covered, matching what the default (Anthropic 1P) mode does for the same input.

Evidence — bench measurement

3 trials × 3 task sizes × 2 modes, all using the same CC v2.1.144 binary and the same prompt fixtures:

| Task | Mode | T1 cache_creation | T2 cache_creation | T3 cache_creation |
|---|---|---|---|---|
| 50k inline | CC + 1P direct | 135,372 | 133,082 | 0 (full read of T2) |
| 50k inline | CC + Bedrock direct | 135,372 | 0 (full read) | 0 (full read) |
| 150k inline | CC + 1P direct | 398,282 | 398,282 | 0 (full read) |
| 150k inline | CC + Bedrock direct | 398,282 | 398,282 | 0 (full read) |
| 300k inline | CC + 1P direct | 790,540 | 792,830 | 0 (full read) |
| 300k inline | CC + Bedrock direct | 6,482 ⚠️ | 6,800 ⚠️ | 61,957 (timeout trial) |

At 50k and 150k both modes cache correctly. At 300k the Bedrock-direct path writes only ~6.5k tokens to cache (≈1.7% of the prompt) — every trial is effectively cold pre-fill.

Control test — Bedrock works fine

Direct boto3.bedrock-runtime.invoke_model_with_response_stream against us.anthropic.claude-sonnet-4-6 in us-east-1, with the same ~350k-token prompt and one explicit cache_control: {"type": "ephemeral"} block on the user text content:

| Trial | Condition | RequestId | TTFT | input_tokens | cache_creation | cache_read |
|---|---|---|---|---|---|---|
| 1 | no marker | <redacted> | 18.4s | 393,558 | 0 | 0 |
| 2 | no marker | <redacted> | 30.2s | 393,558 | 0 | 0 |
| 3 | marker, WRITE | <redacted> | 19.3s | 3 | 393,555 | 0 |
| 4 | marker, HIT | <redacted> | 4.3s | 3 | 0 | 393,555 |
| 5 | marker, HIT | <redacted> | 4.5s | 3 | 0 | 393,555 |

Bedrock cached 393,555 tokens (full prompt) on the first call and served warm reads on the next two — TTFT collapsed from ~24s to ~4.5s. So at 300k context, Bedrock honors cache_control correctly. The bug is on the CC client side, in how it constructs the request body for the Bedrock transport at large prompt sizes.

Steps to Reproduce

  1. Generate a ~300k-token inline prompt (e.g., synthetic log lines + a marker line + a question). Anything well above the 150k threshold.
  1. Run via Claude Code on Anthropic 1P (control):

``bash
ANTHROPIC_BASE_URL=https://api.anthropic.com \
ANTHROPIC_API_KEY=<your-anthropic-key> \
ANTHROPIC_MODEL=claude-sonnet-4-6 \
claude --bare -p "<300k-token prompt>" --output-format stream-json --verbose | \
grep -o 'cache_creation_input_tokens":[0-9]*' | head -3
``

Observe cache_creation_input_tokens ≈ 790,000 on the first turn.

  1. Run via Claude Code on Bedrock direct:

``bash
CLAUDE_CODE_USE_BEDROCK=1 \
AWS_PROFILE=<profile> \
AWS_REGION=us-east-1 \
ANTHROPIC_MODEL=us.anthropic.claude-sonnet-4-6 \
claude --bare -p "<same 300k-token prompt>" --output-format stream-json --verbose | \
grep -o 'cache_creation_input_tokens":[0-9]*' | head -3
``

Observe cache_creation_input_tokens ≈ 6,500 — the bug.

Likely root cause (untested hypothesis)

Looks similar in shape to #50213 (subagent system-context block placed after the cache marker), but on the user-content path rather than the system-prompt path, and only triggering above ~150k tokens. The Bedrock transport may be splitting the prompt into chunks differently than the 1P transport and only attaching the marker to a small leading chunk.

Why this matters

For real-world CC usage on Bedrock with large repo context (extended sessions, big code files inlined, MCP servers with large state) this turns multi-second warm-cache requests into ~30-75s cold pre-fills every turn, and charges the full uncached input-token rate every turn (vs the 90% cache-read discount). At Sonnet 4.6 input pricing this is roughly $1.05/turn ($3/M × 350k) instead of $0.10/turn warmed.

Environment

  • Claude Code: v2.1.144 (also reproduced on v2.1.145)
  • Platform: Windows 11 + native Windows binary
  • Bedrock model: us.anthropic.claude-sonnet-4-6 cross-region inference profile
  • Region: us-east-1
  • Boundary: bug appears between 150k (works) and 300k (broken). Did not bisect further.

Notes

  • Not yet known whether this affects Vertex transport (CLAUDE_CODE_USE_VERTEX=1) at the same context size — please consider checking both.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗