Skip to main content

Command Palette

Search for a command to run...

Error Handling in JavaScript: Try, Catch, Finally

Things go wrong in code — and that's okay. Learn how to handle errors gracefully so your app doesn't crash and your users don't panic.

Updated
5 min read
Error Handling in JavaScript:
Try, Catch, Finally

What Are Errors in JavaScript?

Imagine you're cooking and you accidentally pick up salt instead of sugar. Something unexpected happened — and if you don't notice, the whole dish is ruined. Errors in JavaScript are similar: they're unexpected things that happen while your code is running.

There are two main kinds of errors you'll come across:

Syntax Errors happen when you write JavaScript that the browser can't understand — like a spelling mistake in your code. These are caught before the code even runs.

Runtime Errors happen while your code is actually running. These are the tricky ones, because everything looks fine until something breaks. Here are the most common ones:

  • ReferenceError : Using a variable that doesn't exist

  • TypeError : Doing something invalid with a value's type

  • RangeError : A number is outside the allowed range

  • SyntaxError : Invalid JavaScript code structure

Here are some real examples of runtime errors that can crash your app:

// ReferenceError — variable doesn't exist
console.log(username); //  username is not defined

// TypeError — calling something that isn't a function
let score = 42;
score.toUpperCase(); //  numbers don't have toUpperCase()

// TypeError — property of null
let user = null;
console.log(user.name); //  Cannot read properties of null

Why runtime errors are dangerous

When a runtime error occurs and you don't handle it, JavaScript stops executing your code completely. Users see a broken page. That's a bad experience — and that's exactly what error handling helps you prevent.


Using try and catch Blocks

The try...catch statement is JavaScript's main tool for handling errors. The idea is simple: you try to run some code, and if it fails, you catch the problem and handle it gracefully instead of crashing.

Think of it like a safety net. The acrobat (your code) tries the trick. If they fall, the net (the catch block) catches them — and the show goes on.

try {
  // Code that might cause an error goes here
  let user = null;
  console.log(user.name); // This will throw an error
} catch (error) {
  // This runs ONLY if an error happened above
  console.log("Oops! Something went wrong:", error.message);
}

// Output: Oops! Something went wrong: Cannot read properties of null

The error object that gets passed into catch has two very useful properties:

try {
  undefinedFunction();
} catch (error) {
  console.log(error.name);    // "ReferenceError"
  console.log(error.message); // "undefinedFunction is not defined"
}

Graceful failure

Withouttry...catch, one error can crash your entire app. With it, you can show a friendly message to the user, log the error for debugging, and keep the rest of the app running normally. This is calledgraceful failure— failing without making things worse.

Here's a practical example — fetching user data from an API:

async function loadUserProfile(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    const user = await response.json();
    console.log("Welcome,", user.name);
  } catch (error) {
    // Network failed? API down? We handle it here.
    showErrorMessage("Could not load profile. Please try again.");
    logErrorToServer(error); // Save for debugging later
  }
}

The finally Block

Sometimes you need code to run no matter what — whether the try block succeeded or the catch block fired. That's what finally is for.

A great real-world example: a loading spinner. You turn it on before a network request, and you always need to turn it off when you're done — success or failure.

function fetchData() {
  showSpinner(); // Turn on loading indicator

  try {
    const data = getDataFromAPI();
    displayData(data);
  } catch (error) {
    showError("Failed to load data.");
  } finally {
    hideSpinner(); //  Always runs — success OR failure
  }
}

When to use finally

Usefinallyfor cleanup tasks: closing database connections, hiding loading spinners, releasing file handles, or resetting UI state. It's your guarantee that the cleanup code always runs.

You can even use try...finally without a catch block if you just want guaranteed cleanup but don't need to handle the error yourself:


Throwing Custom Errors

JavaScript lets you create and throw your own errors using the throw keyword. This is useful when you want to signal a problem with bad input, failed validation, or any condition your code considers invalid.

function divide(a, b) {
  if (b === 0) {
    throw new Error("Division by zero is not allowed!");
  }
  return a / b;
}

try {
  const result = divide(10, 0);
} catch (error) {
  console.log(error.message);
  // "Division by zero is not allowed!"
}

You can also use built-in error types to be more specific:

function registerUser(age) {
  if (typeof age !== 'number') {
    throw new TypeError("Age must be a number");
  }
  if (age < 18) {
    throw new RangeError("You must be 18 or older to register");
  }
  console.log("Registration successful!");
}

try {
  registerUser(15);
} catch (error) {
  if (error instanceof RangeError) {
    console.log("Age check failed:", error.message);
  } else {
    console.log("Unexpected error:", error.message);
  }
}

Pro tip: Custom error classes

For larger projects, create your own error classes by extendingError. This makes it easy to identify different types of errors in yourcatchblocks and handle them differently.

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

class NetworkError extends Error {
  constructor(message) {
    super(message);
    this.name = "NetworkError";
  }
}

try {
  throw new ValidationError("Email is invalid");
} catch (error) {
  if (error instanceof ValidationError) {
    showFormError(error.message); // Show to user
  } else if (error instanceof NetworkError) {
    showNetworkBanner(); // Show offline message
  }
}

Happy coding!

Found this helpful? Share it with a fellow developer.