Skip to content
HTTP 304 Not Modified — What It Means & How to Debug

HTTP 304 Not Modified — What It Means & How to Debug

DodaTech Updated Jun 20, 2025 4 min read

HTTP 304 Not Modified indicates the cached version of a resource is still valid — the server tells the client to use its local cached copy without re-downloading.

What It Means

The HTTP 304 Not Modified status code is a caching response. It tells the client that the requested resource has not changed since the last time it was fetched. Instead of re-sending the full resource, the server responds with 304 and an empty body, instructing the browser to use its locally cached copy.

This status code is only returned when the client sends conditional headers — If-Modified-Since or If-None-Match — that include the last modified date or ETag from a previous response. The server compares these values against the current resource state and returns 304 if nothing has changed.

When It’s Sent

  • Browser refreshing a page with cached assets (CSS, JS, images)
  • API clients sending If-None-Match with stored ETags
  • Proxy and CDN revalidation checks
  • Browser navigating back/forward through history
  • Static file servers returning unchanged files

Real Example

curl -v https://example.com/style.css \
  -H "If-Modified-Since: Fri, 20 Jun 2025 10:00:00 GMT"

Expected response if the file hasn’t changed:

> GET /style.css HTTP/1.1
> Host: example.com
> If-Modified-Since: Fri, 20 Jun 2025 10:00:00 GMT
>
< HTTP/1.1 304 Not Modified
< Date: Fri, 20 Jun 2025 12:00:00 GMT
< ETag: "abc123"
< Cache-Control: max-age=3600
<

No file content is sent — the response body is empty and the browser uses its cached style.css.

How to Debug

Browser DevTools

  1. Open the Network tab
  2. Reload the page
  3. Look for requests with status 304 in the Size column (often shows “from disk cache”)
  4. Click the request and check the Headers tab for If-Modified-Since and If-None-Match in Request Headers
  5. The Response Headers show 304 confirming the cached version is fresh

curl

# First request to get the ETag
curl -I https://example.com/script.js

# Look for the ETag header in the output, then use it:
curl -I https://example.com/script.js \
  -H "If-None-Match: \"abc123\""

If the resource hasn’t changed, the response is 304 Not Modified with no body.

Postman

Send a GET request and note the ETag or Last-Modified header in the response. Then send the same request with the If-None-Match header set to that ETag value. The response changes from 200 to 304.

How to Fix

If caching behavior seems wrong:

  • Server-side: Ensure your server sends ETag or Last-Modified headers — without these, the client can’t send conditional requests
  • Cache-Control: Set appropriate Cache-Control headers — max-age tells the client how long to cache before revalidating
  • Weak ETags: If using weak ETags (prefixed with W/), the server checks semantic equivalence, not byte-for-byte identity
  • Static files: For Nginx, ensure etag on; is in the config; Apache enables ETags by default for static files
  • Force refresh: Hold Ctrl (Cmd on Mac) while clicking reload to bypass cache and force a full re-download

Common Causes

ScenarioWhat HappensWhy It Matters
Page reloadCSS/JS files return 304 if unchangedPage loads faster from cache
Browser historyNavigated pages return 304Instant back/forward navigation
API pollingClient sends ETag and gets 304Reduces bandwidth and server load
CDN revalidationEdge node checks origin with If-None-MatchKeeps cached content fresh
Image galleryViewed images return 304 on re-visitFaster gallery navigation

FAQ

Is a 304 Not Modified an error?
No. A 304 is a success response for caching purposes. It means the client’s cached copy is fresh and no data transfer is needed. It reduces bandwidth and improves load times. You should only investigate if you’re getting 304 when the resource has actually changed.
How do I force a 304 to update when the content changes?
You don’t need to — the server automatically compares the If-Modified-Since or If-None-Match values against the current state. When content changes, the server returns 200 OK with the new content and updated headers. If you’re still getting 304 after a change, check that the server’s file modification timestamp is updating correctly.
Can I cache API responses with 304?
Yes. REST APIs can use ETags and Last-Modified headers to enable conditional requests. The client includes these in subsequent requests, and the server returns 304 when data hasn’t changed. This is especially useful for endpoints that return large datasets that rarely change.

Related Codes

  • HTTP 200 OK — the server returns the full resource when it has changed
  • HTTP 301 Moved Permanently — the resource has moved, cache the new URL
  • HTTP 412 Precondition Failed — conditional headers don’t match server state
  • HTTP 404 Not Found — the previously cached resource no longer exists

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro