HTTP 304 is not an error: Understanding ETag and browser cache revalidation

ネットワーク・RFCカテゴリを表すパンダのイラスト Networking / RFC

About this article
This article was created using an automated generation workflow utilizing generative AI. Based on the international HTTP standards RFC 9110 and RFC 9111, as well as MDN primary documentation, we have organized the relationship between the 304 response and caching.

Verification status: 📘 Official specification verified – actual communication / browser operation not performed

When inspecting a website using developer tools, you may see "304 Not Modified" in the Network list. Because images and styles are displayed even though the body is not delivered, you might wonder if it is a communication error or if the cache is corrupted. 304 is not a standard failure, but rathera response that indicates previously saved content can continue to be used. Understanding this as a mechanism to avoid unnecessary body transfer makes troubleshooting easier. We will follow revalidation using ETag and If-None-Match with concrete examples, and clarify the differences among 304, 200, and no communication. While HTTP 428 and 412 covered in another article focus on preventing update overwrites, the main subject here is cache determination regarding whether display resources retrieved via GET need to be fetched again.whether display resources retrieved via GET need to be fetched againAs a cache determination.

ItemSupported environment and conditions
TargetHTTP GET/HEAD, browsers, and intermediary caches
Tools used for observationBrowser network developer tools such as Chrome, Edge, and Firefox
Required costNo additional paid services or API keys required
Investigation scopeChecked RFC rules and MDN descriptions. No actual measurements on specific sites.
Main Constraints304 may not be observed on resources that do not support conditional requests

First step to try: Inspect network traffic before and after 304

Please use publicly available images, CSS, or other non-sensitive resources for observation. There is no need to record or republish authenticated screens, cookies, or personally identifiable headers. The following three steps are methods for readers to try, which does not imply successful reproduction in the current writing environment.

  1. Open the Network panel in your browser's developer tools. First, make sure "Disable cache" is turned off. Load the page normally and select one image or CSS request.

  2. Check if Response Headers contain ETag, Last-Modified, Cache-Control, etc. Distinguish between the initial load where the status is 200 and the body is received, and subsequent reloads where stored resources might be used.

  3. After a normal reload, compare Request Headers (If-None-Match or If-Modified-Since), response status, and transfer size. If a 304 occurs, verify what conditions were used for the query.

A 304 is not guaranteed. If the browser determines the cached version is fresh, it may not query the network and instead show indicators such as "from memory cache" or "from disk cache". Hard reloads or disabling the cache changes these conditions. Conversely, if the resource has been updated, a 200 with a new body is returned, sodo not conclude a failure just because a 304 did not appearis an important point to keep in mind.

200 and 304: What is received and when

On the initial GET, the server returns 200 OK along with the image or CSS content. Identifiers such as ETags and storage conditions are returned at that time, allowing the client to cache the body if it is cacheable. When revalidation is required later, the client can query whether the local version is still valid using a conditional GET.

For example, if the initial response contains ETag: "rev-7", subsequent requests can specify If-None-Match: "rev-7". If the server compares this with the current representation and determines that the conditions match and no changes have been made, it returns 304 Not Modified. A cache capable of selecting stored representations can then reuse that body. If changes have been made, a 200 with a new body may be returned.

ScenarioDummy communication for explanationResult
InitialGET -> 200, ETag: "rev-7"Retrieve body and identifier
Re-verificationGET, If-None-Match: "rev-7"Querying local version
Same version304 Not ModifiedUse cached body
New version200 OK, new ETagRetrieve updated body

304 does not mean that the URL never changes.It means the stored representation can be reusedbased on that conditional request. Server-side content may change at another time, or different representations may be selected depending on request conditions. Therefore, simply comparing 304 and 200 based on the URL alone is insufficient.

According to RFC 9110, a 304 response is intended for conditional GET or HEAD requests. While a 304 itself does not contain a response body for rendering, it may include necessary headers such as Date, ETag, Vary, and Cache-Control. Caches can identify stored responses and update relevant headers in accordance with RFC 9111 rules.The ability to display a page without receiving a new bodyis due to reusing previously stored content in this manner.

Is an ETag the same as a hash value?

An ETag is an identifier assigned by the server to a representation. While some implementations derive it from a file content hash, it is not necessarily a hash like SHA. Servers are free to choose their own generation method. Assuming that 'because the value is a string, it must be a file hash' can lead to incorrect judgments regarding update checks and reproducibility.

Weak ETags, which begin with a W/ prefix, also exist. Weak comparison does not guarantee that the representation bytes are strictly identical. While weak comparisons are relevant in some cache revalidation scenarios, careful consideration is required when using them to prove file integrity. The "rev-7" value used in this example is a fictitious value for explanatory purposes and does not represent an actual site record.

Last-Modified indicates the last modification timestamp provided by the server. Clients may send conditional GET requests with a timestamp in If-Modified-Since. However, because timestamps are subject to precision limitations and update management issues, they do not convey the exact same information as an ETag.

If both conditions are included in the request, RFC 9110 specifies thatIf-None-Match takes precedence and If-Modified-Since is ignoredIt is defined in this way. This does not mean adding the two conditions together. Check which one is present in the Request Headers and distinguish what is being used as the determination factor.

MechanismClient ConditionsTarget to Check
ETagIf-None-MatchComparison of stored representation and identifier
Last Modified TimeIf-Modified-SinceUpdates after specified time
304Response to conditional GET/HEADCan the stored body be reused?

When a file cannot be retrieved despite a 304 response

Typical browsers have a mechanism to store and reuse previous responses. However, if a custom HTTP client manually attaches If-None-Match, it may receive a 304 from the server even though no stored image exists on the client itself. Because a 304 does not include the image body, saving only that response to a file cannot restore the original image.

This does not mean the server sent an empty file, but ratherthe prerequisite that there is a body to reuse locally is not met.If you are sending only conditional GET requests using a tool without caching, you need to retrieve the actual content using an unconditional GET depending on your purpose. Adjust the retry method to match the client specification, and do not repeat the same conditional request indefinitely.

Even if the transfer size of a 304 displayed in the browser is small, the screen presented to the user is composed of previously stored HTML or CSS. Therefore, having small transfer bytes and having no data for the user are different things. If an operation issue occurs, check not only the HTTP status code, but also whether the representation stored in the cache is selected.

In configurations involving CDNs or reverse proxies, separate cache evaluations may operate between the browser and the relay layer, and between the relay layer and the origin. Even if a 304 is visible in the browser, it does not necessarily represent the result of a request that reached the origin. It is important to clarify the observation point, such as which network or logs you are examining.

no-cache does not mean no-store

The Cache-Control directive no-cache has a misleading name.no-cache does not strictly prohibit storage, but rather indicates that stored responses must be validated before reuse.If revalidation results in a 304, the stored body may be used. The belief that 304 is impossible when no-cache is present is incorrect.

On the other hand, no-store is an instruction to prohibit storage. Expecting revalidation using a stored body for a resource with this directive may not result in a 304 as expected. If the stored version is still fresh due to conditions like max-age, it may be reused directly without revalidation traffic.

ConditionTypical behaviorCommon misunderstanding
Fresh cacheMay be reused without communicationNormal even without 304
no-cacheValidate before reuseNot a storage prohibition
no-storeDo not store responsesDifferent from no-cache
Stored version requiring validationCan result in 304 or 200Not necessarily always 304

The Disable cache feature in browser developer tools is not an HTTP header equivalent to server-side Cache-Control. It is a browser-side feature intended to alter observation methods during development. Even if checking this option makes the 304 response disappear, it cannot be concluded that the server cache configuration is broken.

Troubleshooting steps when CSS fails to update

If CSS that should have been updated appears outdated, clearing all caches immediately can erase evidence of the cause. First, record the target file URL, status, conditional headers in Request Headers, and ETag and Cache-Control in Response Headers. For sites using versioned URLs, also verify whether the request destination has switched to a new URL.

Next, determine whether no communication is occurring, a cached version is being reused via a 304 response, or an updated version is being returned with a 200 response. If there is no communication, the cache may still be fresh. For a 304 response, verify the match between the identifier provided by the client and the current representation on the server. If it is a 200 response, check whether a new body is received or examine the CSS application order and separate file imports.

Even when troubleshooting issues where a 304 response is returned but the screen is not updated, first verify which file the 304 corresponds to. The appropriate action varies depending on whether the HTML returns a 200 response while only the CSS returns a 304, or whether images and scripts have different caching conditions. Rather than universally labeling everything as a cache failure, evaluating issues per resource helps pinpoint the problem location.

Conversely, receiving a 200 response every time is also normal. Possible reasons include a policy not to store caches, the absence of conditional requests, or resource updates. Avoid setting "increasing the 304 ratio" as the sole improvement target; instead, evaluate whether correct content is displayed at appropriate timings and whether unnecessary data transfers are minimized.

Do not treat 304 as an error in operational monitoring

In HTTP status classifications, 3xx codes are treated as redirects, but 304 serves a different purpose than standard URL redirection via Location headers. It is a response sent by a server that received a conditional GET or HEAD request to indicate that an existing representation can be used. Monitoring that simply flags any status other than 200 as a failure may generate false alarms for normal revalidation.

However, if an API client does not handle caching and always expects a complete JSON body, a 304 response may be unexpected. In such cases, before immediately blaming the server, verify whether the client is sending conditional headers and whether it retains the stored body upon retrieval. Even if behavior is compliant with HTTP, application-level implementation mismatches will cause issues for users.

When sharing investigation results, recording the browser version, resource type, cache-disable toggle state, confidentiality of the target URL, and observed request/response headers separately makes reproduction easier. Do not publish raw logs containing cookies, authentication tokens, internal hostnames, or personal information as-is.

Diagram: Why the screen displays correctly even when a 304 response contains no body

To understand the meaning of HTTP 304,newly arrived data via communicationandpreviously stored datamust be distinguished. For example, suppose an image is fetched for the first time, resulting in a 200 OK response and a body, which is then stored along with an ETag. On a subsequent display, a conditional GET with an If-None-Match header may be sent to check whether that stored version can be used.

sequenceDiagram
    participant B as ブラウザー
    participant C as 保存済みキャッシュ
    participant S as Webサーバー
    B->>S: 初回GET
    S-->>B: 200と本文とETag
    B->>C: 本文と条件を保存
    B->>C: 保存版を利用できるか照合
    C-->>B: 再検証が必要
    B->>S: If-None-Matchを付けたGET
    S-->>B: 304 本文なし
    B->>C: 保存済み本文を再利用
    C-->>B: 画像やCSSを表示

The diagram illustrates a hypothetical communication flow to explain the mechanism. Actual routing differs across real browsers, caches, and CDNs. A server returning a 304 does not send a new body because the response assumes an available stored version can be used. However, this does not guarantee correct display in cases where no stored version exists, the selected representation differs, or the cache is corrupted.

Distinguishing between no communication, 304, and 200

If a resource stored in the cache is still fresh, the network query may be omitted entirely. This differs from a state where a 304 communication occurs. Note that selecting "Disable cache" or forced reloading solely to observe 304 responses alters conditions compared to normal usage.

flowchart TD
    A["保存済み資源を表示したい"] --> B{"保存版を利用できるか"}
    B -->|"新鮮"| C["再検証通信なしで利用する場合"]
    B -->|"再検証が必要"| D["条件付きGETを送信"]
    B -->|"保存版なし"| E["通常GETで本文を取得"]
    D --> F{"サーバーの判定"}
    F -->|"変更なし"| G["304 保存済み本文を利用"]
    F -->|"変更あり"| H["200 新しい本文を取得"]

This diagram simplifies decision-making, and behavior is actually influenced by Cache-Control, Vary, and browser implementation details. A 200 status does not indicate a problem, nor does the absence of a 304 status mean caching is disabled. Decisions should be made by reviewing request and response headers, storage conditions, and reload methods together.

Outline the investigation process when only the CSS is outdated

Suppose that on a fictional site, the CSS has been updated, but the old design is still displayed for only some users. First, check the URL of the affected CSS and whether the final response in the Network tab corresponds to no communication, 304, or 200. If it is 304, compare the request headers such as If-None-Match or If-Modified-Since with the returned conditions such as ETag. If it is 200, check whether the expected new response body is being returned.

If you blindly delete all caches at this point, the conditions for reproducing the issue may be lost. First, record the occurrence time, URL, conditional headers, browser used, and reload method. If proxies or CDNs are present, isolate where the served asset was cached. Avoid pasting sensitive information such as authentication cookies or signed URLs into reports; narrow down the cause from the read data before determining the necessity of configuration changes.

Summary: 304 confirms the use of a cached version

304 Not Modified indicates that, as a result of a conditional GET/HEAD request, it was determined that the stored representation can be reused. It is expected by specification that a 304 response itself has no body. By examining ETag, If-None-Match, Last-Modified, Cache-Control, and the presence or absence of a stored body together, it becomes easier to distinguish between optimized bandwidth usage and actual bugs.

Official Documentation

This article is an explanation of official specifications and observation procedures and is not a reproduction report based on actual captured traffic logs. Behavior in specific browsers and actual rendering on CDNs or WordPress have not been verified.

Document information

Article title
HTTP 304 is not an error: Understanding ETag and browser cache revalidation
Published
Updated
Source
https://papanda925.com/?p=18473&lang=en

License: Text and original figures for which this site holds the relevant rights are available under CC BY 4.0 , unless otherwise noted. This article may include content created or edited with generative AI. If code has a separate license notice or a linked GitHub repository license, that license takes precedence for the code. Quotations, third-party materials, images, and trademarks are excluded from this license. Usage policy

Copied title and URL