304 - Not Modified
HTTP 304 Not Modified means conditional request found that the cached representation is still valid.
Last reviewed: February 12, 2026|Editorial standard: source-backed technical guidance
What Does Not Modified Mean?
Cache revalidation succeeded, so the client should reuse its cached representation instead of downloading the body again.
Common Causes
- -If-None-Match or If-Modified-Since matched current representation state.
- -Resource has not changed since cached validator was issued.
- -CDN or proxy revalidation confirms cached variant freshness.
How to Fix Not Modified
- 1Validate ETag and Last-Modified generation so validators stay consistent across origin instances.
- 2Inspect If-None-Match and If-Modified-Since behavior alongside Cache-Control and Vary directives.
- 3Purge or revalidate stale cache entries when validator drift appears after deployment changes.
Step-by-Step Diagnosis for Not Modified
- 1Capture conditional request headers and validator values associated with 304 responses.
- 2Verify ETag/Last-Modified generation consistency across replicas, regions, and representation variants.
- 3Inspect Cache-Control/Vary policies across browser, CDN, proxy, and origin paths.
- 4Retest with controlled validator scenarios (cold cache, changed resource, unchanged resource).
Validator Generation and Consistency Checks
- -Compare validator outputs across nodes (example: same resource returns different ETags per replica).
- -Audit weak vs strong validator usage (example: weak ETag used where byte-level equality is required).
Cache Revalidation Policy Alignment
- -Validate Vary dimensions are included in cache keying (example: gzip and br variants sharing one validator incorrectly).
- -Inspect CDN revalidation behavior (example: edge sends stale `If-None-Match` after origin deploy).
Implementation Examples
curl -i -X GET https://api.example.com/v1/resource -H 'If-None-Match: "etag-v1"'
# Response:
# HTTP/1.1 304 Not Modified
# ETag: "etag-v1"const response = await fetch('https://api.example.com/v1/resource', {
method: 'GET',
headers: { 'Accept': 'application/json', 'If-None-Match': '"etag-v1"' }
});
if (response.status === 304) {
console.error('Handle 304 Not Modified');
}import requests
response = requests.get(
'https://api.example.com/v1/resource',
headers={'Accept': 'application/json', 'If-None-Match': '"etag-v1"'}
)
if response.status_code == 304:
print('Handle 304 Not Modified')How to Verify the Fix
- -Confirm changed resources return 200 with updated payload and unchanged resources return 304 only when valid.
- -Validate cache freshness, validator headers, and revalidation behavior across browser and CDN paths.
- -Monitor 304 to 200 ratio and stale-content incidents to verify stable conditional caching behavior.
How to Prevent Recurrence
- -Generate deterministic validators and keep cache keys aligned with representation variants and Vary policy.
- -Add regression tests for conditional GET and HEAD behavior across deployment and replica changes.
- -Track cache and validator anomalies with alerts tied to stale-content and revalidation failure signals.
Pro Tip
- -include build/version hash in validator generation inputs for dynamic resources to avoid cross-release stale cache collisions.
Decision Support
Compare Guide
403 Forbidden vs 404 Not Found: When to Hide Resources
Use 403 for explicit access denial, or 404 to conceal resource existence when security policy requires reducing endpoint and object enumeration risk.
Compare Guide
404 Not Found vs 410 Gone: Missing vs Permanent Removal
Learn when to return 404 (missing or temporary absence) versus 410 (intentional permanent removal), including redirect and cache implications.
Playbook
Resource State Playbook (404 / 410 / ResourceNotFound)
Use this playbook to separate temporary missing-resource lookups from permanent removals, then fix scope, lifecycle, and identifier drift safely.
Official References
Provider Context
This guidance is specific to HTTP services. Always validate implementation details against official provider documentation before deploying to production.