Native Bedrock Codex GPT-5.6 Sol lacks explicit cache controls, producing high cache-write spend

Resolved 💬 13 comments Opened Aug 9, 2026 by apexethdev Closed Aug 21, 2026
💡 Likely answer: A maintainer (scottleibrand, contributor) responded on this thread — see the highlighted reply below.

Summary

Native Codex CLI requests to Amazon Bedrock Mantle cannot opt into GPT-5.6 Sol explicit prompt caching. On an agentic coding workload, this has produced a large volume of cache-write tokens and materially higher cost.

This is related to #35300, but adds independent production usage evidence from the native amazon-bedrock provider.

Environment

  • Codex CLI: 0.147.0
  • Provider: native amazon-bedrock
  • Endpoint: Bedrock Mantle Responses API, us-east-1
  • Model: openai.gpt-5.6-sol

Observed production usage

For the completed days 2026-08-05 through 2026-08-08, Cost Explorer usage quantities and the Bedrock rate card produced the following cache-aware estimate for Sol:

| Requests | Cache-write tokens | Estimated cache-write cost | Estimated total cost |
|---:|---:|---:|---:|
| 3,656 | 171.94M | $1,182.09 | $1,386.46 |

Cache writes were about 85% of the model's estimated spend.

A local Codex session also reported 76 Sol requests with 6.709M cache_write_input_tokens, zero cached_input_tokens, and an average of about 88K cache-write tokens per request. There were no client errors in the corresponding CloudWatch metrics.

These are usage-derived estimates, not finalized AWS invoice amounts.

Investigation

Codex already emits a session-scoped prompt_cache_key, but the request types for both HTTP and WebSocket Responses requests do not include either:

  • prompt_cache_options
  • prompt_cache_breakpoint

The built-in Amazon Bedrock provider config exposes transport/auth settings, not structured request-body transformation, so this cannot be configured through config.toml.

AWS documents explicit cache mode for GPT-5.6 on Bedrock specifically for agentic workflows with long stable instructions/tool definitions followed by changing tool and user content. That matches the workload above.

Requested behavior

  1. Add support for serializing prompt_cache_options for GPT-5.6-capable Responses providers.
  2. Add a typed prompt_cache_breakpoint field to supported input content blocks.
  3. Provide a provider/model capability gate and a safe placement strategy at the end of Codex's measured stable instruction/tool prefix.
  4. Surface cache reads and cache writes in per-turn usage telemetry so users can diagnose costly full-prefix rewrites.

Scope

This report does not claim that every cache write is a defect. Cold starts, genuinely distinct prompts, forks, and compaction can all require writes. The issue is that native Bedrock Codex currently has no way to use the documented explicit-cache mechanism for the stable-prefix case.

View original on GitHub ↗

13 Comments

tylerchen0123-sudo · 16 days ago

For the telemetry part of this request, one semantic detail is worth making explicit in tests/UI: cache_write_input_tokens should be shown as its own diagnostic bucket, but it should not automatically be added on top of provider input_tokens when deriving total usage/cost unless the provider contract says those buckets are disjoint. The same caution already applies to cached_input_tokens, which is a subset of Codex input.

I keep cache-write/read as separate observability fields in a small local Codex rollout monitor: https://github.com/tylerchen0123-sudo/CODEX-Inspection-Guidelines-for-Dosage/blob/main/collector.py

A useful cross-provider fixture here would contain nonzero input + cache-read + cache-write and assert both: (1) the raw provider fields survive serialization unchanged, and (2) the presentation/cost layer does not accidentally double-count a subset bucket. That would make the new Bedrock cache controls measurable without baking one provider’s bucket semantics into every downstream consumer.

kevmyung · 13 days ago

@rka-oai, tagging you since you worked on #36981, which appears related to this issue.

After upgrading from 0.146.0 to 0.147.0 with the Amazon Bedrock provider, the cache write-to-read ratio increased from 0.08 to 8.84, and my daily cost rose to at least 5x its previous level.

After rolling back to 0.146.0, the ratio immediately returned to 0.025 with a 97% cache-read rate.

Would you mind taking a look at whether remote compaction could be invalidating the Bedrock prompt cache?

devonpmack · 13 days ago

Potential patch implementing the request-body side of this issue (explicit prompt_cache_options + a prompt_cache_breakpoint on the last cacheable developer-prefix block):

https://github.com/openai/codex/compare/main...devonpmack:codex:feat/gpt-56-explicit-prompt-cache

scottleibrand contributor · 12 days ago

I had Sol put together a workaround/fix for this: https://github.com/scottleibrand/codex/pull/1. Mantle implicit caching was not advancing across growing session history, causing Codex to repeatedly write most of the prompt instead of reading the previously cached prefix. So this sets explicit cache breakpoints at stable and recent-history boundaries, reproducing the same desired input caching behavior seen with the direct OpenAI inference.

Testing against production workloads on Mantle, we saw:

  • 35 Bedrock/Luna rollouts
  • 1,486 provider responses
  • 30 multi-request sessions: all cache-healthy
  • 97.771% aggregate cache-read ratio after seed requests
  • 99.958% aggregate read-or-write coverage
  • Lowest per-session coverage: 99.849%

Since direct upstream PRs are by invitation only, I had it PR this on my own fork: https://github.com/scottleibrand/codex/pull/1

I don't necessarily expect anyone to want to merge this workaround upstream as-is, but affected users should be able to test/use this until a proper fix is in place.

This does not directly solve https://github.com/openai/codex/issues/35300, which appears to involve cross-session cache-key/reuse behavior. The explicit cache-control plumbing may nevertheless be relevant, so I’m referencing it here.

jdcodes1 · 9 days ago

Confirmed the request-shape gap on main (1f41cc5d92): the Responses request structs carry only prompt_cache_key (codex-api/src/common.rs#L41, #L270, threaded into both HTTP and WS request builders) — no prompt_cache_options, no per-block breakpoint field anywhere in codex-api. So on Bedrock, where caching for Sol is explicit-opt-in rather than implicit, every request re-writes the full prefix, which is exactly the 85%-cache-write / zero-cache-read profile you measured.

Two observations for the implementation:

  1. Codex already knows where the breakpoint belongs. The request assembly has a clean seam between the stable prefix (base instructions, tool specs, environment context — constant across a session's turns) and the per-turn tail; the natural placement is after the last stable item, and codex constructs that boundary itself, so "safe placement strategy" doesn't need heuristics — just a marker emitted at assembly time when the provider capability gate is on.
  2. Your item 4 (usage telemetry) has a cheap first step: cache_write_input_tokens/cached_input_tokens already come back in Bedrock usage payloads (your local session read them), but codex's token accounting only tracks cached_input from first-party responses — surfacing both fields per-turn in /status + exec --json usage would let users see the miss pattern without Cost Explorer archaeology. That also helps first-party users diagnose cache-invalidation churn (#38524's compaction-thrash pattern produces the same signature).

The capability gate can hang off the provider config rather than model info, since this is a Bedrock-Mantle contract detail — which also keeps the change orthogonal to the catalog-staleness problems in #37813.

celia-oai contributor · 7 days ago

this is most likely caused by cache miss caused by newly turned on web search tool and we are working with bedrock team for the fix. In the meantime, feel free to disable the tool as a workaround (in config, add web_search = "disabled"). note codex will still be able to perform web search via other tools such as shell commands

apexethdev · 7 days ago
this is most likely caused by cache miss caused by newly turned on web search tool and we are working with bedrock team for the fix. In the meantime, feel free to disable the tool as a workaround (in config, add web_search = "disabled"). note codex will still be able to perform web search via other tools such as shell commands

thanks for the reply. Will try this out and confirm. Do we expect a real fix at some point?

kevmyung · 7 days ago

I tested this on 0.148.0 with Bedrock and the workaround works. With web_search = "cached", cache reads stayed at zero; with web_search = "disabled", caching resumed normally.

ppearcy · 7 days ago

I feel like this should be treated as a critical bug. It can quickly chew up thousands of dollars of tokens and you only notice if you are paying close attention. Whatever caused the regression should be reverted or fixed asap.

apexethdev · 7 days ago
I feel like this should be treated as a critical bug. It can quickly chew up thousands of dollars of tokens and you only notice if you are paying close attention. Whatever caused the regression should be reverted or fixed asap.

Yep.

I've a bill for $1200+ now that would have normally been 300USD.

Thankfully I checked a day later or it would have been far worse.

But still, really annoying when I didn't do anything wrong.

jakswa · 6 days ago

I lump myself into $1k+ bill territory due to this bug. I wonder if AWS would be amenable to a discount or something 😩

celia-oai contributor · 6 days ago

the deployment of the fix has gone through on the bedrock side for web search tool. I verified that the fix works in us-east-2, us-west-2 and us-east-1. Closing this out - feel free to open a new one if the issue persists.

NetBr3ak · 5 days ago

promptCacheKey tells the provider where to route the request. cache_control is
what marks the prefix as cacheable. Send the first where the second is expected
and every request comes back fine while nothing gets cached at all.

A read costs 0.1 of a normal input token. So on a stable prefix that mistake
means paying about ten times what you should, on every repeated token, until
somebody reads the raw request body.

Translation layers keep doing this. There are open issues right now with the
same shape against an Anthropic to Bedrock translator in one of the open source
gateways, and against a vendor orchestration layer in a big enterprise
suite.