304 HTTP Origin: Network Last updated 9 Oct 2026

HTTP 304 Not Modified

The cached copy is still valid, so the server sends no body and the client reuses its cache.

Exact message you may see not modified
Seen on: Nginx Apache

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

  1. Version static files (app.css?v=123 or hashed filenames)
  2. Purge the CDN cache after deploys
  3. In fetch, use cache: 'no-store' for data that must be fresh
  4. Treat 304 as success when you send conditional headers yourself

Detailed fix by platform

Nginx

  1. 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

  1. Use mod_expires/mod_headers; with multiple servers, FileETag MTime Size avoids 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 304

How to diagnose

  1. Freshness — Is the user actually seeing stale content?
  2. Validators — ETag / Last-Modified values before and after deploy
  3. Caching layers — Browser, CDN, proxy — which one served it?

🔧 Still not fixed?

Many errors look alike. If the steps above didn’t solve it, one of these is probably what you’re facing:

Where this error sits

Origin: Network. Errors that are often confused with or caused by this one (click to open):

103 — HTTP 103 Early Hints (HTTP)1031200 — Cloudflare Error 1200: Cache connection limit (Cloudflare)1200301 — HTTP 301 Moved Permanently (HTTP)301412 — HTTP 412 Precondition Failed (HTTP)41257014 — ERROR: canceling statement due to statement timeout (PostgreSQL)57014ANR — ANR: Application Not Responding (Input dispatching timed out) (Android)ANRcf-cache-status: DYNAMIC — Cloudflare not caching: cf-cache-status DYNAMIC / BYPASS / MISS every time (Cloudflare)cf-cache-status: DYNA…Error establishing a Redis connection — WordPress: Error establishing a Redis connection (object cache) (WordPress)Error establishing a …304

Explore the map of this error Full error map →

🧠 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.

💬 What worked for others

No tips yet — did something else fix this for you?

Share what worked for you

Tips are checked by an editor before they appear. Links are removed.