How does fetch work, and how do you handle errors with it?

JavaScript Async Intermediate 1–2 Yrs2–3 Yrs Coding 1 min read

Quick Answer

fetch(url) returns a promise that resolves to a Response. The catch: it only rejects on a network failure — a 404 or 500 still resolves. You must check response.ok (or response.status) yourself and throw. Body parsing (response.json()) is a separate promise.

fetch gives you a promise for a Response object. The thing everyone gets caught by is that it doesn't reject for HTTP error statuses — a 404 or a 500 is still a “successful” fetch as far as the promise is concerned. Only a network error rejects. So I always check response.ok and throw if it's false. Then reading the body is a second await — response.json(). For timeouts I use an AbortController and pass its signal. A lot of teams use axios instead because it handles the non-2xx rejection and JSON parsing automatically.

  • Pattern: const res = await fetch(url); if (!res.ok) throw new Error(res.status); const data = await res.json();.
  • Timeout / cancellation: pass signal from an AbortController — fetch(url, { signal }) then controller.abort().
  • fetch doesn't send cookies cross-origin unless credentials: 'include'.
  • Libraries like axios add automatic JSON, non-2xx rejection, interceptors and timeouts — hence their popularity.