Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

fetch() gives JavaScript a promise for a Response, not a promise for parsed JSON. When response headers are available, that promise can fulfill even if the server returned an HTTP error such as 404. Your code must check the status and then separately read the response body.

What happens when you call fetch()?

  1. JavaScript creates a request. You can pass a URL or a Request object, with options for details such as the method, headers, body, mode, and credentials. If you do not specify a method, the default is GET. MDN’s Fetch API guide describes these request inputs.

  2. The browser processes it under Fetch rules. The request does not necessarily travel directly from your code to the origin server. Redirects, cross-origin rules, Content Security Policy (CSP), service workers, and other browser processing can affect what happens. The WHATWG Fetch Standard describes this unified model.

    Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  3. fetch() returns a promise for a Response. In a normal request, the promise fulfills when a response is available—MDN describes this as occurring as soon as the server responds with headers. The Response includes information such as the HTTP status and headers; it is not the parsed body value.

  4. Your code decides what to do with the response. Check its status, then call an appropriate body-reading method such as json() or text(). That method returns its own promise, so receiving the response and consuming its body are separate asynchronous stages.

Why doesn’t fetch() reject on a 404?

fetch() treats an HTTP response and a request failure as different outcomes. A server response with status 404 or 504 is still an HTTP response, so the fetch promise can fulfill with a Response. Check response.ok or response.status to decide whether the status is acceptable to your application. MDN’s fetch() reference documents this distinction.

A rejected promise indicates that the request did not produce a usable response for the caller. Documented causes include a malformed URL or a network error. Aborting a request with AbortController produces an AbortError; that is not an HTTP status response.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do you check the status and then read the body?

Use one await for the response and another for its body. For example:

const response = await fetch("/api/data");
if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();

The first await gets the Response. The second waits for json() to read and parse its body. If you need a different representation, use a suitable body method such as text() instead.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

What changes what JavaScript can observe?

Cross-origin requests and CORS

For a cross-origin request, the default mode is cors. A simple request may be sent, but the browser withholds the response from JavaScript unless the server returns a suitable Access-Control-Allow-Origin header. A non-simple request may require a preflight request before the browser sends the actual request. These rules determine whether the calling code can read a cross-origin response; see MDN’s CORS guidance for Fetch.

The opaque response from no-cors

Setting mode: "no-cors" does not make arbitrary cross-origin response data readable. It produces an opaque response: JavaScript cannot access its headers or body. It is not a workaround for CORS when your code needs to inspect the returned data.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Service workers

A service worker can receive fetch events for explicit fetch() calls and other browser requests. Its handler can use the network, return a cached response, or synthesize a response. If the handler does not call respondWith(), the browser makes the original request. The details are in MDN’s service worker fetch-event reference.

Redirects and browser policy

Redirects, CSP, cross-origin handling, and service workers are part of the Fetch model, so the exact path depends on the request and browser context. The WHATWG standard summarizes its model as: “A request goes in, a response comes out.” That does not mean every request is an unmediated trip from JavaScript to the origin server.

Keep the outcomes separate

  • Fulfilled promise: JavaScript has a Response; it still needs to check the status and, if needed, consume the body.
  • HTTP error status: The server returned a response, but the status may require application-specific handling.
  • Rejected promise: The request failed before a usable response was returned, or it was aborted.
  • Opaque response: A response exists, but its headers and body are not exposed to JavaScript.
  • Service-worker response: The response may come from cache or be synthesized rather than being the result of a direct network request.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.