Azure OpenAI GPT-5.6: cached prefix is evicted after ~5-8 minutes instead of the documented 30-minute minimum

Arndt, Patrick 0 Reputation points
2026-08-28T11:36:52.51+00:00

Scenario

We run GPT-5.6 deployments on a Standard pay-as-you-go Azure OpenAI resource in Sweden Central and rely on prompt caching to keep input cost down for long, stable system prompts.

The documentation states for GPT-5.6:

prompt_cache_options.ttl sets a minimum cache lifetime. [...] A cached prefix remains eligible for reuse for at least 30 minutes, but the service might retain it longer.

Prompt caching with Azure OpenAI

We measure a cached prefix disappearing in under 8 minutes of inactivity, which matches the pre-GPT-5.6 in-memory policy ("typically clears caches within 5 to 10 minutes of inactivity") that the same article says no longer applies to GPT-5.6.

Environment

  • Azure OpenAI, Standard pay-as-you-go, region Sweden Central
  • Deployments: gpt-5.6-terra, gpt-5.6-sol, gpt-5.6-luna
  • v1 API: POST {endpoint}/openai/v1/responses and /openai/v1/chat/completions
  • Plain HTTPS requests, Python standard library only, no SDK involved

The deployments are Standard, not PTU-M: they report cache_write_tokens and accept prompt_cache_breakpoint, neither of which PTU-M supports.

Repro

A byte-identical ~4,015-token prefix is sent at 0 min, +8 min, +20 min and +35 min. prompt_cache_key is set on every request, and the request rate is 3 requests per checkpoint, far below the documented ~15/min threshold.

import json, time, urllib.request
from datetime import datetime

URL = "https://<resource>.openai.azure.com/openai/v1/responses"
KEY = "<api key>"
PREFIX = "Please ignore this test text. " * 500  # ~4,000 tokens


def call(label):
    body = {
        "model": "gpt-5.6-terra",
        "max_output_tokens": 16,
        "prompt_cache_key": "probe-a",
        "input": [{"type": "message", "role": "user", "content": [
            {"type": "input_text", "text": PREFIX},
            {"type": "input_text", "text": "Reply with the word OK."},
        ]}],
    }
    req = urllib.request.Request(
        URL, data=json.dumps(body).encode(),
        headers={"Content-Type": "application/json", "api-key": KEY},
    )
    with urllib.request.urlopen(req, timeout=120) as resp:
        u = json.load(resp)["usage"]
    d = u["input_tokens_details"]
    print(f"{datetime.now():%H:%M:%S} {label:10} input={u['input_tokens']} "
          f"cached={d.get('cached_tokens', 0)} writes={d.get('cache_write_tokens')}")


call("warmup")
call("immediate")
time.sleep(8 * 60)
call("+8 min")
time.sleep(12 * 60)
call("+20 min")
time.sleep(15 * 60)
call("+35 min")

Result

Three request shapes were sent side by side, each with its own prefix and prompt_cache_key:

Variant Request shape
A default implicit mode, no explicit breakpoint
B prompt_cache_options {mode: implicit, ttl: 30m} + prompt_cache_breakpoint on the input_text block
C prompt_cache_options {mode: explicit, ttl: 30m} + prompt_cache_breakpoint on the input_text block
11:15:45 warmup    A input=4014 cached=0    (  0.0%) writes=4011
11:15:46 warmup    B input=4015 cached=0    (  0.0%) writes=4012
11:15:47 warmup    C input=4015 cached=0    (  0.0%) writes=4004
11:15:48 immediate A input=4014 cached=4011 ( 99.9%) writes=0
11:15:50 immediate B input=4015 cached=4012 ( 99.9%) writes=0
11:15:52 immediate C input=4015 cached=4004 ( 99.7%) writes=0
11:23:53 +8 min    A input=4014 cached=0    (  0.0%) writes=4011
11:23:54 +8 min    B input=4015 cached=0    (  0.0%) writes=4012
11:23:55 +8 min    C input=4015 cached=0    (  0.0%) writes=4004
11:35:57 +20 min   A input=4014 cached=0    (  0.0%) writes=4011
11:35:58 +20 min   B input=4015 cached=0    (  0.0%) writes=4012
11:35:59 +20 min   C input=4015 cached=0    (  0.0%) writes=4004
11:51:00 +35 min   A input=4014 cached=0    (  0.0%) writes=4011
11:51:01 +35 min   B input=4015 cached=0    (  0.0%) writes=4012
11:51:03 +35 min   C input=4015 cached=0    (  0.0%) writes=4004

The writes value on every cold call shows the prefix being written to the cache again, so this is eviction rather than a routing miss. Because cache writes are billable on GPT-5.6, each request after a short pause costs more than an uncached request would have.

Control: the same model on OpenAI direct keeps the prefix

To rule out that this is simply how GPT-5.6 caching behaves, the same prefix was sent to gpt-5.6-terra through the OpenAI API instead of Azure, using the same script and the same intervals:

13:40:02 warmup     input=5014 cached=0    (  0.0%) writes=5011
13:40:04 immediate  input=5014 cached=5011 ( 99.9%) writes=0
13:46:07 +6 min     input=5014 cached=5011 ( 99.9%) writes=0
14:00:10 +20 min    input=5014 cached=5011 ( 99.9%) writes=0

On OpenAI the prefix is still fully cached after 20 minutes and writes stays 0, meaning the original entry is being read rather than rewritten. On Azure the same model has already lost the entry at +8 min and pays a fresh cache write. The model and the request shape are identical; only the provider differs.

Troubleshooting already done

Each of these was measured, not assumed. All variables below made no difference:

  • Network path — identical results through our reverse proxy and when calling the Azure endpoint directly.
  • API surface — identical results on /openai/v1/responses and /openai/v1/chat/completions, same deployment, same moments.
  • Explicit breakpoints — variants B and C follow the documented example (breakpoint on an input_text / text content block).
  • Deploymentterra, sol and luna were sent the same payload at the same moments and all three lost the prefix between the immediate call and +8 min.
  • Prefix stability — the payload is generated once per process and reused byte-for-byte; 4,015 tokens, well above the 1,024 minimum.
  • Request rate — 3 requests per checkpoint, far below ~15/min per key.

Question

Is the documented 30-minute minimum cache lifetime actually in effect for GPT-5.6 Standard pay-as-you-go deployments in Sweden Central? The same model reached through the OpenAI API retains the prefix for at least 20 minutes, so this does not appear to be inherent to GPT-5.6 caching. If these deployments are still served by the pre-GPT-5.6 in-memory retention policy, is there a configuration on our side that enables the documented behaviour?

These describe a different failure (cached_tokens returning 0 on every call). In our case caching works and then expires early, so they are not duplicates:

Azure OpenAI in Foundry Models
0 comments No comments

3 answers

Sort by: Oldest
  1. Divyesh Govaerdhanan 11,725 Reputation points MVP Volunteer Moderator
    2026-08-29T23:11:13.97+00:00

    Hello Arndt, Patrick,

    Welcome to Microsoft Q&A,

    One thing to confirm first. Your repro code doesn't show prompt_cache_options in the request body, but your troubleshooting list says you tested explicit breakpoints with it. Could you share the exact payload from that specific test? For GPT-5.6 and later, the only supported config is:

    "prompt_cache_options": { "mode": "explicit", "ttl": "30m" }
    

    ttl: "30m" is documented as the default even without setting it explicitly, but mode may still matter. If mode wasn't set to "explicit" in that test, it's worth rerunning with both fields present together.

    If you've already confirmed both fields were set and still saw eviction at 5-8 minutes, then this isn't a config issue on your end. It directly contradicts the documented "at least 30 minutes" minimum for Standard PAYG on GPT-5.6+. (PTU-M doesn't apply here since Standard PAYG is what supports caching breakpoints on 5.6+ anyway.) At that point, I'd open an Azure support ticket instead of testing further. Region-specific eviction behavior like this needs the service team to confirm, documentation alone can't settle it.

    One more thing to rule out, unrelated to your specific issue: the 24-hour "Extended Retention" feature doesn't apply to 5.6 anyway (it only covers 5.5, 5.4, 5.3-codex, 5.2, 5.1, and 4.1), so that's not a setting you're missing.

    Please Upvote and accept the answer if it helps!!

    Was this answer helpful?

    0 comments No comments

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. Arndt, Patrick 0 Reputation points
    2026-08-31T07:57:45.3266667+00:00

    Thanks for looking at this.

    Both fields were set. The repro block I posted only showed variant A, which was my mistake. Here is the actual variant C payload:

    {
      "model": "gpt-5.6-terra",
      "max_output_tokens": 16,
      "prompt_cache_key": "probe-c",
      "prompt_cache_options": { "mode": "explicit", "ttl": "30m" },
      "input": [
        {
          "type": "message",
          "role": "user",
          "content": [
            {
              "type": "input_text",
              "text": "<~4,000 tokens of fixed filler text>",
              "prompt_cache_breakpoint": { "mode": "explicit" }
            },
            { "type": "input_text", "text": "Reply with the word OK." }
          ]
        }
      ]
    }
    

    Sent to POST {endpoint}/openai/v1/responses, same object reused byte-for-byte on every call. The 99.7% on the immediate call in my C rows shows the breakpoint is being honored, the entry just isn't there at +8 min. A and B behaved identically, so mode makes no difference to the lifetime.

    So yes, both fields confirmed and eviction still at 5-8 minutes.

    I can't post the full repro code here. I tried but my answer got automatically deleted.

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.