Community tool — not affiliated with Anthropic

Cache Eviction Observatory

Tracking Claude Code in-TTL previous_message_not_found prompt-cache losses across the machines that report them: every data point below was parsed locally in a volunteer's browser and submitted as approved aggregate numbers only. One machine is one row — a second submission from the same machine updates its row instead of adding another.

Machines reporting
one row per machine, not per person
Observed in-TTL losses
legitimate TTL expiries excluded
Re-billed tokens
cache writes charged again after a loss
Observation period
earliest to latest submitted day
Check your own data →

Why this observatory exists

The short history, including the part that argues against the headline.

Since spring 2026, some Claude Code users have seen their usage allowance drain abnormally fast, to the point where a 5-hour limit window was exhausted in tens of minutes. A GitHub report from May (#63282) was closed automatically without a response.

In August, attention turned to a diagnostic the server itself writes into local session logs: message.diagnostics.cache_miss_reason. That field made losses measurable from server-stamped records instead of gut feeling.

An honest counterpoint belongs here: most raw hits are not a bug. In the operator's own data, 78% of raw previous_message_not_found records were legitimate expiries after long idle periods. This site excludes those and counts only losses inside the cache TTL.

Controlled observations followed: four sessions on the same machine lost their cache within the same single minute, and one cache entry vanished 24 seconds after it was created. The same signature has been confirmed on three independent accounts.

Whether this is a handful of broken environments or a widespread problem can only be answered with structured data from many machines. Collecting that is what this site is for. Discussion continues in anthropics/claude-code#87966.

What a diagnosis shows you Example data

Point the check at your own logs and this is the shape of what comes back. Every number in the framed block below is a synthetic sample generated by assets/demo.js: not an observation, not anyone's submission, not the maintainer's own machine.

Why the sample is synthetic: the submission schema carries daily aggregates only and has no hour-level field, on purpose, so that submitting cannot reveal when you work. No real submission can back an hour-level heatmap, so none is used here.

Requests scanned
In-TTL losses
inside 30 min (main) / 5 min (subagent)
Iron losses
idle gap under 5 minutes
Re-billed tokens
cache writes charged again
Loss rate
in-TTL losses / requests
losses (left axis) loss rate % (right axis) clean day
idle (no requests) grey shading = requests that hour (darker = more) red = losses (number in the cell; click it and the table below switches to that hour)

Run this on your own logs → Parsing happens in your browser; log files never leave your machine, and nothing is submitted until you press the share button.

Fleet daily loss rate Real submissions

In-TTL losses as a share of that day's requests, one line per reporting machine. Vertical alignment across machines points at server-side events; a step down that holds across machines points at a fix being deployed. Every day on this axis is a UTC day, the same cut for every submission — which is what makes lining two machines up on the same date mean anything.

Breakdown by environment Real submissions

The same submissions, grouped by one self-reported environment field. The sample size is printed on every row, and a group below the floor shows its counts without a rate.

Pick which self-reported field the submissions are grouped by. The table below regroups on the one you pick; the loss rate is recomputed per group, and the sample size is printed on every row.

ValueSubmissions (n)RequestsIn-TTL lossesLoss rate
Raw values, one row per submission
NicknameClientPlanSessionsRequestsIn-TTLLoss rate
  • Every environment field is self-reported at submission time. Nothing in the pipeline can verify it.
  • Request volume differs by an order of magnitude between machines, so these denominators are not comparable in size: one heavy machine can carry a whole group.
  • Groups with fewer than 5 submissions show counts only. Rows are ordered, not ranked; what a row supports is "this is what has been submitted so far".

Submissions Real submissions

Aggregate totals per submission. No timestamps, no session IDs, no file paths; the schema cannot carry them. Nicknames are stored masked, so the row you submitted is marked from this browser's own record instead. Click a column header to sort: it reorders the rows on screen and changes nothing else on the page.

Methodology & trust

What counts as a loss, and why you can verify every step yourself.

  • Source of truth: the server-stamped diagnostic message.diagnostics.cache_miss_reason = previous_message_not_found in your local session logs (~/.claude/projects/**/*.jsonl). Nothing is inferred; only records the server itself marked are candidates.
  • TTL-strict judgment: a candidate counts as a loss only if the idle gap to the previous request in the same session file is under 30 minutes (main session) or under 5 minutes (subagent). Anything longer is a legitimate TTL expiry and is excluded.
  • Iron losses: the subset with an idle gap under 5 minutes, where the cache could not have expired under any published TTL.
  • Dedup & cost: events are deduplicated by requestId; the re-billed cost of a loss is that request's cache_creation_input_tokens.
  • Which day a request counts on: this observatory, and every submission in it, cuts days by UTC. Submissions from many countries are summed day by day, and cutting each one by its own local date would scramble the fleet's daily totals. The check page is the other way round on purpose: it is one person's own diagnosis, so its charts, heatmap and per-event times are drawn in the reader's own timezone, detected from their browser and named on screen. Same requests, same totals; only the day boundary moves, so a request near midnight can appear on one date there and the neighbouring date here. The payload preview on that page says so before you send it.
Trust model: parsing runs in your browser, locally: log files never leave your machine. What gets transmitted is only the aggregate numbers you explicitly approve (daily counts and totals). The diagnosis page can optionally keep your result in that browser's own storage, but only if you press the save button and confirm: that copy stays on your computer, never reaches a server, and one button deletes it. And because this site has no build step, the code that runs is exactly the code in the repo. Read it line by line before you run it.
Is my conversation content uploaded?
No. Parsing happens entirely inside your browser. You can verify this yourself: open the F12 Network tab and run a diagnosis; no network request appears. Nothing is transmitted before you press the share button, and pressing it sends only the aggregate-number JSON previewed on screen.
Does this site keep anything on my computer?

Only if you ask it to. By default a diagnosis exists just in the open tab and is gone when you close it. On the check page you can press “Save to this browser” and confirm the prompt; that writes the totals, the daily rows and the hour-by-hour counts into that browser's local storage.

What a save is, and is not: it stays inside that browser on that computer, it is never sent to a server, and “Clear saved results” deletes it immediately and completely. It exists so a later run can start the day after your last submission instead of re-sending a period you already shared. Log file paths, session IDs, requestIds and conversation text are not written to it, the same fields the submission schema excludes. On a shared or public computer, do not save.

How can I trust what this code does?

The code that runs is exactly the repo's files; there is no build step, so you can compare the browser's view-source against the repo line by line. This is the whole thing:

  • assets/parse.js — the scoring engine, running in your browser. Same rules as the CLI scripts/check_cache_loss.py, with an automated test comparing both outputs.
  • assets/charts.js — drawing only. It does no scoring.
  • assets/store.js — the check page's optional local save. Browser storage only, never the network, and only after you confirm.
  • functions/api/submit.js — the only code that runs on a server. Called only when you press submit; it validates the schema and commits to this repo.
  • data/submissions.json — the public dataset this page reads. One submission is one commit, so the full history is auditable.
  • wrangler.toml — even the deployment configuration is public: there is no hidden backend.
Does running this affect my Claude account?
No. It only reads log files. It makes no contact with your Anthropic account or the API.
I got in-TTL losses. What now?
Please leave your result on anthropics/claude-code#87966. A zero result is equally valuable data: knowing healthy accounts exist also helps narrow down the cause.
What becomes public if I submit?
Only the aggregate and daily numbers you approved in the preview, plus the optional nickname. Every submission lands as a public commit in the repo, so the full submission history is auditable.
Is this an official Anthropic site?
No. This is a community tool with no affiliation with Anthropic.
Check your own data →