To handle errors with the JavaScript Fetch API, check for two different outcomes: a rejected request and a fulfilled response with an unsuccessful HTTP status. A 404 or 500 normally does not reject fetch(); inspect response.ok or response.status yourself. Then keep reading and parsing the response body inside your error-handling flow, and account for cancellation with AbortController.
Why doesn’t fetch throw on a 404?
fetch() rejects for request-level failures, such as a network error or malformed URL. An HTTP error status is different: when the server returns a response, fetch() usually fulfills with a Response, even if its status is 404 or 500. As MDN puts it, “The fetch() function will reject the promise on some errors, but not if the server responds with an error status like 404: so we also check the response status and throw if it is not OK.” MDN: Using the Fetch API.
As an Amazon Associate I earn from qualifying purchases.
This means a try/catch around fetch() alone does not catch unsuccessful HTTP statuses. Treat status validation as a separate step and decide which statuses your application considers acceptable.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →How should you check the HTTP status?
Use response.ok for the standard success check: it is true for status codes in the 200 range. Use response.status when your application needs to branch on a particular code or include the status in an error. The Response.ok and Response.status properties expose these values.
#1 Best Overall
async function getJson(url, { signal } = {}) {
const response = await fetch(url, { signal });
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
Throwing here converts an HTTP response your application considers unsuccessful into an exception that callers can catch. If different statuses need different handling, branch on response.status instead of treating every non-OK response identically. Preserve useful response details when reporting application-specific errors.
How do you handle request, status, and body errors together?
The request can reject before you receive a response. After it fulfills, status validation can identify an HTTP failure. Even after a successful status check, reading or parsing the body can fail. Keep all three stages within a coherent error-handling flow, while retaining the stage and details needed for diagnosis.
Rank #2
async function getJson(url, { signal } = {}) {
try {
const response = await fetch(url, { signal });
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
// Handle request, HTTP-status, body-read, parse, or abort errors.
throw error;
}
}
The await before response.json() matters: it makes a rejection from the asynchronous body read or JSON parsing part of the surrounding try/catch. You can instead allow the function to return that promise directly, as in the earlier example, but then this local catch will not handle a later rejection from that returned promise. Choose the structure based on where the error needs to be handled.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minutePC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11What can fail while reading the response body?
Methods such as response.json() and response.text() read the body asynchronously. The read or parse can reject, so a fulfilled fetch() does not guarantee that the body is available or valid JSON. If you need to distinguish malformed JSON from other failures, handle the parsing step separately and report that distinction.
A response body is a stream and ordinarily can be consumed only once. If two parts of your code need to read it, clone the response before the first read and give each consumer its own response copy. See MDN’s guidance on locked and disturbed streams.
How should cancellation with AbortController be handled?
Pass an AbortController signal to fetch() and call abort() when the request should be canceled. Handle AbortError according to the workflow: cancellation may be an expected outcome, such as when a user navigates away, rather than an error worth showing as a failure.
Rank #4
const controller = new AbortController();
try {
const response = await fetch(url, { signal: controller.signal });
// Check response.ok, then read the body.
} catch (error) {
if (error.name === "AbortError") {
// Treat expected cancellation appropriately for this workflow.
} else {
throw error;
}
}
// Call when cancellation is needed:
controller.abort();
Cancellation can still affect body consumption after the response headers have arrived: aborting before the body is read can make that read reject with AbortError. Therefore, if the body is part of the operation, keep its read within the cancellation-aware error flow. MDN documents this behavior in Canceling a request.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →What can you diagnose from an opaque response?
A response with type "opaque", commonly associated with a no-cors request, exposes limited information: its status is 0, its body is null, and its headers are not readable. That leaves application code without the usual status and body details for diagnosing the server result. See Response.type.
Best Value
Which failure stage should you handle?
| Failure stage | What the code sees | Useful handling |
|---|---|---|
| Request | fetch() rejects, for example because of a network problem or malformed URL. |
Catch the rejection; diagnose the request-level failure and decide whether the operation should be surfaced or retried. |
| HTTP status | fetch() fulfills with a Response, including for statuses such as 404 or 500. |
Check ok or status; branch or throw according to application requirements. |
| Body read or parse | A method such as json() or text() can reject asynchronously. |
Await the body method inside the relevant error-handling flow; retain enough detail to identify a read or parse problem. |
| Cancellation | The request or body read can reject with AbortError. |
Distinguish expected cancellation from failures that should be reported or acted on. |
| Opaque response | Status is 0, body is null, and headers are unavailable. |
Recognize that ordinary response diagnostics are not exposed for this response type. |
Retry behavior depends on the request and application; these failure stages do not imply a universal retry rule. A retry decision should account for the operation and the error information available at that stage.
Quick Recap
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.




