I used to think that if a fetch() request failed, the catch block would handle it.
Something like this:
try {
const response = await fetch("/api/users/123");
const user = await response.json();
console.log(user);
} catch (error) {
console.error("Request failed:", error);
}
But there's a detail here.
If the server returns a 404 or 500, fetch() doesn't reject the promise.
You still get a response object.
So this code:
const response = await fetch("/api/missing");
console.log(response.status); // 404
console.log(response.ok); // false
works normally, assuming the server actually responds with a 404.
The catch block won't run just because the status code indicates an error.
To handle that, you need to check response.ok yourself.
async function getUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
Now you can catch HTTP errors too:
try {
const user = await getUser(123);
console.log(user);
} catch (error) {
console.error(error);
}
response.ok is true for status codes from 200 to 299.
One more thing: calling response.json() doesn't mean the response contains valid JSON. If the server sends an HTML error page, for example, JSON parsing can throw a separate error.
So checking the HTTP status before parsing the body is usually a good idea.
It's a small distinction, but worth remembering when using the native Fetch API.
Top comments (0)