Crux Read real HTTP exchanges — first fetch, revalidation, weak-vs-strong matching, and a range request — then predict the status the server returns and the highest-leverage fix.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min
ETag bugs are diagnosed in the wire log, not the source. Read each exchange the way you would read it in DevTools or a tcpdump, then pick what the server returns — and, where something is wrong, the fix a senior engineer reaches for first.
Goal
Practise the loop you run in every caching incident: read the request and response headers, trace the validator comparison, and predict the status — 200 vs 304 — before you touch a config.
The content has not changed since the first fetch. What does the server return to the second request, and what crosses the wire?
Heads-up A match means the client already holds the current version; re-sending the body is exactly what conditional requests exist to avoid.
Heads-up 204 means the request succeeded with no content to return at all; revalidation has its own dedicated status, 304 Not Modified, which tells the client to reuse its cached copy.
Heads-up That is long-polling, a different mechanism. A conditional GET completes immediately with 200 or 304.
Exchange 2 — weak tag, strong precondition
GET /report.html HTTP/1.1Host: cdn.example.comIf-None-Match: "v42"# server's current validator for this resource:# ETag: W/"v42"
Quiz
Completed
The client sent the strong tag in If-None-Match; the server currently holds the weak form of the same value. What status comes back?
Heads-up For If-None-Match the comparison is weak by definition; the W/ prefix is disregarded, so the tags match and the server sends 304.
Heads-up 412 applies to If-Match preconditions on writes; for If-None-Match the weak comparison succeeds here, giving 304, not an error.
Heads-up Mixing forms is well-defined: If-None-Match always compares weakly, so this is a valid 304, not a protocol error.
Exchange 3 — resuming a download
GET /video.mp4 HTTP/1.1Host: media.example.comRange: bytes=1000000-If-Range: W/"clip-build-9"# server's current validator:# ETag: W/"clip-build-9"
Quiz
Completed
The client is resuming a download with If-Range carrying a weak validator that matches the server's current weak ETag. What does the server return?
Heads-up If-Range demands byte-for-byte identity; a weak validator only promises semantic equivalence and cannot guarantee the existing partial bytes line up, so the range is refused and a full 200 is sent.
Heads-up If-Range never produces 304; it chooses between a 206 partial response (strong validator matches) and a full 200. A weak validator forces the full 200.
Heads-up 416 is for ranges outside the resource bounds. Here the range is valid; the weak validator simply downgrades the response to a full 200, not an error.
Exchange 4 — the per-node regression
# Request lands on pod A, which minted the client's cached tagGET /api/config HTTP/1.1If-None-Match: "pod-a-counter-7"HTTP/1.1 304 Not Modified# Next poll round-robins to pod BGET /api/config HTTP/1.1If-None-Match: "pod-a-counter-7"HTTP/1.1 200 OKETag: "pod-b-counter-3"Content-Length: 8192
Quiz
Completed
Identical config content, yet pod A returns 304 and pod B returns 200 for the same If-None-Match. What is broken, and what is the highest-leverage fix?
Heads-up The content is identical — pod B sends the same 8 KB body. The defect is the token derivation being node-local, not stale data, so restarting changes nothing.
Heads-up Sticky sessions are a workaround that masks the real bug and breaks the moment a pod is replaced. The fix is a content-derived ETag, which makes revalidation correct regardless of which pod answers.
Heads-up That hides the symptom by skipping revalidation, but stale config will now be served past its change. The root cause — inconsistent per-node tokens — still needs a content-derived ETag.
Recap
Every ETag incident is read in the exchange: a matching If-None-Match returns 304 with an empty body but still costs the round-trip; If-None-Match compares weakly, so W/ and strong forms of the same value match; If-Range is the one place that demands a strong validator, so a weak tag forces a full 200 instead of a 206; and when identical content yields different tokens on different pods, the bug is a node-local ETag — fix it by deriving the tag from the content, not the box.