Skip to main content

Command Palette

Search for a command to run...

Error Handling in JavaScript Explained (Try, Catch, Finally with Examples)

Updated
6 min read
Error Handling in JavaScript Explained (Try, Catch, Finally with Examples)

Understanding Errors

What are Errors in JavaScript

In programming, errors occur when something unexpected happens during the execution of your code. When JavaScript encounters an instruction it does not understand or cannot execute, it throws an error.

Think of it like a factory machine running on an assembly line. If a piece of metal gets jammed in the gears, the machine cannot continue its normal operation. It stops completely to prevent further damage.

console.log(x);
console.log("This line will never run");

Here is a step-by-step explanation of what happens

  1. JavaScript reads the first line and tries to print the variable x.

  2. It realizes x does not exist because it was never defined.

  3. JavaScript immediately throws a "ReferenceError" and stops executing.

  4. Because the execution stopped, the second line of code is completely ignored.

Why Error Handling Matters

What happens when code breaks in a real application? Without proper error handling, a single broken line of code can crash your entire webpage, leaving your user staring at a blank, broken screen.

By anticipating and handling errors, you create what developers call a "graceful failure". Instead of the app crashing, you intercept the problem, show the user a friendly warning message, and keep the rest of the application running smoothly.

Try and Catch

Using try and catch

To handle errors safely, JavaScript gives us the try and catch blocks. The try block is where you place your risky code that might potentially fail. The catch block is the safety mechanism that takes over if an error actually happens.

Imagine a tightrope walker at a circus. Walking the tightrope is the risky action (the try block). Most of the time, they make it across perfectly. But if they lose their balance and fall, the safety net below (the catch block) catches them, ensuring the show can safely go on.

try {
  console.log(x);
} catch (error) {
  console.log("Something went wrong, but the app is still running!");
}

Let's break down this execution step-by-step

  1. JavaScript enters the try block and attempts to execute console.log(x).

  2. An error occurs because x is not defined.

  3. Instead of crashing the program, JavaScript instantly jumps into the catch block.

  4. The catch block handles the error by printing our custom message, and the rest of the program safely continues running.

finally Block

What is finally

The finally block is an optional addition to try and catch. The code inside the finally block will always run, no matter what happens. It runs if the try block succeeds, and it runs if the catch block intercepts an error.

Think of leaving a conference room after a meeting. If the meeting was a huge success (the try block worked), you turn off the lights before you leave. If the meeting was a disaster and everyone argued (the catch block ran), you still turn off the lights before you leave. Turning off the lights is the finally block.

try {
  console.log("Attempting to run risky code...");
} catch (error) {
  console.log("An error was caught.");
} finally {
  console.log("This will always run, cleaning things up.");
}

Here is exactly how this works

  1. JavaScript runs the try block successfully.

  2. Because there was no error, the catch block is completely skipped.

  3. JavaScript automatically moves to the finally block and executes it.

  4. If an error had occurred in step 1, the catch block would run, but the finally block would still execute right after it. It is perfectly designed for cleanup tasks, like closing a database connection or hiding a loading spinner.

Throwing Custom Errors

What is throw

JavaScript automatically throws errors for syntax problems or missing variables. However, you can also manually create and trigger your own errors using the throw keyword. This is useful when the code technically works, but it breaks the specific rules of your application.

Think of a referee in a sports game. The players might be running and passing the ball perfectly fine, but if someone steps out of bounds, the referee blows the whistle to stop the play because a specific game rule was broken.

function withdraw(amount) {
  if (amount > 1000) {
    throw new Error("Limit exceeded. You cannot withdraw that much.");
  }
  console.log("Dispensing cash: $" + amount);
}

try {
  withdraw(1500);
} catch (error) {
  console.log("Transaction failed: " + error.message);
}

Let's walk through this step-by-step

  1. We call the withdraw function inside a try block and ask for 1500.

  2. Inside the function, the if statement checks if the amount is greater than 1000. It is.

  3. We use throw new Error() to forcefully generate a custom error with our own message.

  4. Execution stops immediately inside the function, and JavaScript jumps straight to our catch block, printing our custom failure message.

Practical Understanding

Real-World Example

In modern web development, you will use error handling most often when communicating with external servers or APIs. Network requests are highly unpredictable, so they are the perfect place for try and catch.

async function loadUser() {
  try {
    console.log("Connecting to database...");
    const user = await fetchUser(); // Pretend this fetches data from the internet
    console.log("Welcome, " + user.name);
  } catch (err) {
    console.log("Failed to load user. Please check your internet connection.");
  } finally {
    console.log("Hiding loading animation.");
  }
}

Here is the flow explained clearly: We wrap our network request inside a try block. If the user's internet drops while fetching the data, the application does not crash. Instead, it gracefully jumps to the catch block to show a polite error message. Finally, regardless of whether the fetch succeeded or failed, the finally block runs to remove the loading spinner from the screen.

Common Mistakes

When learning to handle errors, we often make a few specific missteps

  • Ignoring errors: Catching an error but leaving the catch block completely empty hides the problem. You will have no idea why your app is failing.

  • Overusing try/catch: You do not need to wrap every single variable declaration or simple math equation in a try/catch. Only use it for risky operations like network requests, reading files, or parsing data.

  • Not using meaningful messages: Throwing generic errors like throw new Error("Bad") makes debugging a nightmare. Be descriptive about exactly what failed.

  • Catching errors but not handling: If you catch an error, you should log it, report it to a monitoring service, or display a fallback UI to the user.

Summary

  • Errors happen during runtime when JavaScript encounters unexpected situations.

  • The try block allows you to test a block of risky code.

  • The catch block acts as a safety net to handle failures without crashing the application.

  • The finally block executes unconditionally, making it perfect for cleanup tasks.

  • The throw keyword allows you to enforce your own application rules by creating custom errors.

  • Proper error handling improves reliability, makes debugging easier, and creates a much better user experience.

More from this blog