◉CLAUDE LABJP
●2.1.288 — Claude Code 2.1.288 (Oct 2) now shows a re-authentication prompt when an MCP server asks for additional OAuth scope mid-call●10/07 — 4 days left until the old spellings of Claude Desktop / Cowork managed-config keys stop being accepted. After the cutoff they fail closed●LIMIT — Reports of hitting usage limits almost instantly on the Max plan have reached 1,498 comments on the official issue. Many readers are looking for a way to isolate the cause●NEW — Before trimming a scheduled task's instruction doc, I counted how many times that one file gets re-read●CONNECT — A request to use one connector with several accounts, work and personal, has drawn 260 comments. Where to draw the line is the real question●BUDDY — A community plea to bring Buddy back has reached 274 comments. It is a good case for thinking about how to live with a retired feature●2.1.288 — Claude Code 2.1.288 (Oct 2) now shows a re-authentication prompt when an MCP server asks for additional OAuth scope mid-call●10/07 — 4 days left until the old spellings of Claude Desktop / Cowork managed-config keys stop being accepted. After the cutoff they fail closed●LIMIT — Reports of hitting usage limits almost instantly on the Max plan have reached 1,498 comments on the official issue. Many readers are looking for a way to isolate the cause●NEW — Before trimming a scheduled task's instruction doc, I counted how many times that one file gets re-read●CONNECT — A request to use one connector with several accounts, work and personal, has drawn 260 comments. Where to draw the line is the real question●BUDDY — A community plea to bring Buddy back has reached 274 comments. It is a good case for thinking about how to live with a retired feature
Articles/Claude Code
⟐ Claude Code/2026-08-19Intermediate

Fixing the Code Doesn't Evict a Broken Page From the Edge Cache

I shipped a fix and the broken page kept serving. The problem was not the code but the edge cache, which had stored a broken HTML response because the store decision looked only at the status code. Here is the integrity guard I now run before every cache write, and the thresholds I had to tune in production.

Claude Code258Cloudflare Workers16Edge CacheNext.js8Operations21

✦ Premium Article

One morning I pushed a fix for a layout break on an article page. The build passed. The deploy succeeded. On my machine the page rendered correctly.

On a different device it was still broken.

A private window showed the same thing. Deploying again changed nothing. I reread the code several times looking for the mistake I must have made, and found nothing, because there was nothing to find. At that point I still had not suspected the cache. The response was returning 200.

The cache was the problem. A broken HTML response had been stored as a healthy one, and it was being served to everyone. My corrected code was sitting behind it, waiting for a request that never reached it.

The blind spot: broken pages that return 200

When you write a cache store decision, the natural thing to check is the status code. That is what I had done. Store 2xx, skip 4xx and 5xx. It is simple, and most of the time it is correct.

The trouble is that an application can be broken and still return 200.

In the Next.js App Router, an exception during rendering hands off to an error boundary (error.tsx or global-error.tsx), which renders a fallback UI. From HTTP's point of view that is a successful response: status 200. The same thing happens when only the article body fails to load and the surrounding shell renders fine. The page exists. There is nothing in it.

A status code tells you that a response was produced. It says nothing about whether that response is worth reading.

Response stateHTTP statusStatus-based decisionWhat the reader gets
Healthy page200StoreFine
Error boundary fallback200StoreBroken
Shell rendered, body empty200StoreBroken
Truncated HTML stream200StoreBroken
Server error500SkipBroken, but refetched

Rows two through four are the hole I fell into. Once stored, those responses stay until the TTL expires or someone purges them. The underlying fault may have lasted a few hundred milliseconds; the outage lasts hours.

What makes this hard to reason about is that the incident is not ongoing. It is frozen. Your logs are clean. You cannot reproduce it. And readers still see a broken page.

The trigger is almost always a momentary failure

It is worth explaining where the broken HTML came from.

The sites I run are Next.js applications deployed on Cloudflare Workers. Article bodies are stored as separate HTML files and read through the static asset binding rather than bundled into the Worker, which is what keeps the bundle under the size limit. I wrote about that arrangement separately in the 62 MiB limit and content split architecture.

That design adds a step: fetching the body is a read that can fail. In the seconds right after a deploy, or occasionally for no visible reason, that read came back empty. It was rare. Not something I saw daily.

Rarity turned out to be no protection at all. A cache converts a rare failure into a permanent state. If one request in ten thousand fails and that one gets stored, the other nine thousand nine hundred and ninety-nine see the failure.

This asymmetry is easy to miss when you are reasoning about probability. I missed it.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦You will be able to decide what belongs in your cache based on whether the body is complete, not on whether the status code happens to be 200
✦You will be able to stop a one-in-ten-thousand render failure from becoming a page that every visitor sees, using a single guard at the write path
✦You will be able to tell within minutes whether a fix that appears not to work is a code problem or a cache problem
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

⟐ Claude Code2026-09-03
Aligning Log Timezones at Display Time, or Fixing Them at Write Time
AdMob, the store reports, and my own logs each ended the day at a different moment. Here is how I went back and forth between display-side and write-side timezone handling, and what I settled on.
⟐ Claude Code2026-08-22
Handing a long job to another session — and the completion marker for when the notification never arrives
How to use notify_when_idle to hear when another Claude Code session finishes, and a small completion marker that keeps you from waiting forever when the notification is dropped.
⟐ Claude Code2026-08-03
Existence Checks Pass, Writes Fail — Probing Capabilities Before an Unattended Run
A directory existing and a directory being writable are two different facts. Measured results from five broken-environment cases, why static clues cannot predict the worst of them, and a capability-probe preflight for unattended Claude Code runs.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links