A layout bug gets fixed. The developer checks the origin server directly and the page is correct. The client loads the live site and it is not. Everyone reaches for the same explanations — a bad deploy, a browser cache, a device-specific bug — and the actual cause is that a content delivery network is still serving a copy of the old asset and will continue to do so for hours.
This wastes a disproportionate amount of time because the symptom points away from the cause. The developer's evidence is genuinely valid: the origin is correct. The client's evidence is also valid: the site is wrong. Both parties are looking at different artefacts and reasonably assuming they are the same one.
Where it bites hardest
Generated assets. A theme or build step that compiles a stylesheet to a stable filename is the classic case: the contents change, the URL does not, and the edge has no reason to fetch again until its time-to-live expires. HTML is usually either uncached or short-lived, so the markup updates immediately while the styling that markup depends on does not. The result is a page that is broken in a way neither version was — new structure, old presentation.
The same pattern catches anything with a stable URL and changing contents: a sitemap, a configuration file fetched at runtime, a JSON feed, a logo that was replaced in place.
Fix the mechanism, not the incident
Purging the cache resolves today's problem and guarantees the same problem next month. The durable fixes, in order of preference:
- Put a version in the URL. Append the file's modification time or a content hash as a query parameter or filename segment. A changed file is a changed URL, so the edge fetches it and no purge is ever required. This is the whole answer for generated assets and it costs one line in most frameworks.
- Separate the cache policy from the deploy. Long-lived caching is correct for versioned assets and wrong for anything with a stable name. Set those policies by path deliberately rather than inheriting one default across everything.
- Purge on deploy, automatically. For the cases you cannot version, make the purge part of the release rather than a thing someone remembers. A purge that depends on memory will be forgotten on the release where it matters.
Diagnosing it in thirty seconds
Before anyone starts rebuilding, establish which artefact is wrong. Request the asset from the edge and read the response headers: a cache status field will tell you whether it was served from cache and how old the stored copy is. Then request the same path directly from the origin, bypassing the edge, and compare. If origin and edge differ, you have your answer and nobody needs to look at the code.
Worth doing this as the first step rather than the last, whenever the report is "the change did not appear". It is a thirty-second check that regularly saves a day.
A note on the human cost
Teams that have been bitten by this once tend to overcorrect into purging everything on every deploy, which throws away the performance benefit they are paying for. The point of an edge cache is that most requests never reach the origin. Keep that, and make correctness a property of how assets are named rather than a manual step performed under pressure.