DEV Community

Soren Sterling
Soren Sterling

Posted on

fetch() doesn't throw on a 404

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);
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

Now you can catch HTTP errors too:

try {
  const user = await getUser(123);
  console.log(user);
} catch (error) {
  console.error(error);
}
Enter fullscreen mode Exit fullscreen mode

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)