HTTP 304 Not Modified
The cached copy is still valid, so the server sends no body and the client reuses its cache.
Meaning
304 is a performance win, not an error. It answers conditional requests (If-None-Match with an ETag, or If-Modified-Since). It becomes a problem when users keep seeing stale CSS/JS/API data, or when code treats 304 as a failure.
Common causes
- Static assets changed but filenames/ETags didn’t (no cache busting)
- ETags differ across servers behind a load balancer, causing needless 200s
- API clients mishandling empty 304 bodies
- Proxy/CDN caching with long max-age
⚡ Quick fix
- Version static files (
app.css?v=123or hashed filenames) - Purge the CDN cache after deploys
- In fetch, use
cache: 'no-store'for data that must be fresh - Treat 304 as success when you send conditional headers yourself
Detailed fix by platform
Nginx
- Long cache for hashed assets, revalidate HTML:nginx
location ~* \.(css|js|png|svg|woff2)$ { expires 30d; add_header Cache-Control "public, immutable"; } location / { add_header Cache-Control "no-cache"; }
Apache
- Use mod_expires/mod_headers; with multiple servers,
FileETag MTime Sizeavoids inode-based ETag mismatches.
Code examples
See the conditional request
bash
curl -sI https://example.com/app.css | grep -i etag
curl -sI -H 'If-None-Match: "65f1-5e2a"' https://example.com/app.css # → HTTP/2 304How to diagnose
- Freshness — Is the user actually seeing stale content?
- Validators — ETag / Last-Modified values before and after deploy
- Caching layers — Browser, CDN, proxy — which one served it?
🧠 Still stuck? Analyze your error
Paste the full message, response headers or stack trace — we'll detect the platform and point to the most likely cause.
Was this page helpful?
Report a correction or suggest an improvement
Last updated 2 Oct 2026