DEV Community

Emmanuel Sunday
Emmanuel Sunday

Posted on

The real reason you need a try and catch block (probing 101)

A lot of junior developers always get told to “put it in the try block.”

“Use a try and catch block”

“You catch the error if the requests fail”

“It helps you avoid having a request crash out”

But without a catch block, if you look closely, we can still handle errors 🙂. Yes.

We could console.error.

Throw new Error().

We could console.log (errors).

Most “external sources” also have error objects.

So, we can technically live without them?

Or so you may think?!!!

Well, sit with me for a sec let's charter.

Exceptions (AKA Try…catch)

Introduced in the programming language CLU (a now-obscure but influential MIT language), exceptions were introduced to make code cleaner.

In 1980, Ada adopted them, then C++.

In 1995, Java made it mainstream with try, catch, and finally.

In 2025, you NEED them.

Let's get their practicality right…

Here's an “exception” implementation in JavaScript().

Python devs, inhale, exhale. Now change the catch block for “exception.” We're good now, right? (JS devs, skip)

Now, what's the significance of “exceptions" here?


try {
  const res = await fetch('/api');
  if (!res.ok) throw new Error(`HTTP error: ${res.status}`);
  const data = await res.json();
  console.log('Data:', data);
} catch (err) {
  console.error('Request failed:', err.message);
}


Enter fullscreen mode Exit fullscreen mode

A good observer could point out we are already handling errors with the “res.ok” condition. So maybe.. It's…redundant?

NB: if (!res.ok) throw new Error(HTTP error: ${res.status}); simply means… if the response is not in the 200-299 range of status code, throw an error.

Now here's the catch.

Any response whether in the 200 status code range (success) or in the 400 (server errors), are still responses.

In other words your fetch request technically went through. Whether it received and returned a failed HTTP request, is a story for another day.

But there's a thousand (I mean, more than two) reasons your fetch request will not even be made, talk more of getting a response like 500.

Network failure

Imagine a user on your app makes a request, and the next second their network trips off.

A try…catch block will gracefully resort your request to the catch block and do whatever the catch block says.

And If you had a catch block like this…

try {
  const res = await fetch('/api');
  if (!res.ok) throw new Error(`HTTP error: ${res.status}`);
  const data = await res.json();
  console.log('Data:', data);
} catch (err) {
  console.error('Request failed:', err.message);
}

Enter fullscreen mode Exit fullscreen mode

… your user gracefully knows they lost connection.

Sooo much better than a blank screen or crashed app.

…at least I think.

Ps: Here's one beauty you should know…

In our example, we said if !res.ok, throw an error.

try {
  const res = await fetch('/api');
  if (!res.ok) throw new Error(`HTTP error: ${res.status}`);
  const data = await res.json();
  console.log('Data:', data);
} catch (err) {
  console.error('Request failed:', err.message);
}

Enter fullscreen mode Exit fullscreen mode

Fun fact: “throw new Error” is a statement that raises an exception (try…catch block), and creates a new instance of error .

If that's confusing, here's what I mean…

In our case, the moment !res.ok, our code stops at the point of “throw new…” and calls the catch block.

Now when the catch block processes…

catch (err) {
  console.error('Request failed:', err.message);
Enter fullscreen mode Exit fullscreen mode

…err.message has the value “HTTP error: ${res.status}” like we passed with throw new Error().

Beautiful isn't it?

Read that twice to understand better.

To simply put, throw new Error() makes your code resort to the nearest catch block in its composition, while passing a value to it.

Server errors

A fetch request may not be received for hundreds of reasons, extra common with external APIs.

The end point may be deprecated, may not be accepting your parameters, or be temporarily down.

Things happen and that's why applications need maintenance.

Try…catch could be one of those maintenance.

One thousand reasons you need a try and catch block…

I remember telling you one thousand reasons earlier on, while arrogantly giving you only two.

Here are other 998 reasons

  1. Error Handling
  • Allows you to catch runtime errors instead of letting the program crash.
  • Ensures your application can gracefully handle unexpected situations.
  1. Control Flow
  • Lets you separate normal logic from error logic.
  • You can decide how to respond to different errors (retry, log, notify, etc.).
  1. Debugging
  • Provides access to the error object (err) so you can inspect the problem.
  • Makes it easier to trace, log, and fix bugs.
  1. Consistency Across Layers
  • Ensures backend servers don’t crash on errors.
  • Helps frontend apps display user-friendly messages instead of breaking the UI.
  1. Support for Asynchronous Code
  • Works with async/await to handle promises that might reject.
  • Consolidates multiple potential failures into one catch block.
  1. Clean, Readable Code
  • Avoids messy error checking everywhere (if statements for every operation).
  • Makes code more structured and maintainable.

I have only 6 here. Now go and find the 992 yourself.

And if you have some here, support us in the comment section.

Have a nice day debugging!

Top comments (0)