Error Handling in JavaScript

Discover how to control the flow of your program and handle unexpected issues to build robust, crash-proof applications with `try...catch`.

Lesson ProgressStep 1 of 9
try {  let data = JSON.parse("...bad json");}catch (error) {  console.log(error.message);}finally {  db.closeConnection();}
0 EXP

Welcome! Let's learn to handle JavaScript errors. Without error handling, one small bug can crash your entire app!

// Your code is running...

The `try...catch` Statement

The `try...catch` statement is the foundation of error handling in JavaScript. It's composed of two main blocks:

  • The `try` block contains code that might "throw" an error. This is where you put your risky operations, like parsing JSON or making an API call.
  • The `catch` block contains code that executes only if an error occurs in the `try` block. It acts as a safety net, receiving an "error object" with details about what went wrong.
try {
  // Risky code goes here
  JSON.parse("{invalid_json"); 
} catch (error) {
  // This code runs because an error was thrown
  console.log("Caught an error!");
}

Without `try...catch`, the `JSON.parse` error would crash your entire script. With it, the error is handled, and your program can continue to run.

System Check

When does the `catch` block execute?

Advanced Holo-Simulations

0 EXP

Log in to unlock these advanced training modules and test your skills.


Achievements

🏆
Error Wrangler

Successfully use `try...catch` to handle a runtime error.

🧹
Cleanup Crew

Correctly structure a `try...catch...finally` block.

🎯
Exception Ejector

Create and `throw` a custom error.

Mission: The Unsafe Division

Complete the `divide` function. It should `throw` a new `Error` with the message "Cannot divide by zero!" if `b` is 0. Use `try...catch` to handle this error and `console.log` the error message.

A.D.A. Feedback:

> System integrity looks stable. Code is valid.

Challenge: Order the Blocks

The `try...catch...finally` structure has a specific order. Drag the blocks into the correct sequence from top to bottom.

catch (error) { ... }
finally { ... }
try { ... }

Challenge: Complete the Syntax

Fill in the missing keywords to create and throw a new error.

if (input < 0) {("Input negative"); }

Consult A.D.A.

Community Holo-Net

Beyond the Crash: A Deep Dive into Robust JavaScript Error Handling

In a perfect world, our code would run flawlessly every time. In reality, errors are a fact of life. Network requests fail, user input is invalid, and servers go down. JavaScript's error handling mechanism, centered around the `try...catch...finally` block, gives us the power to anticipate these problems and handle them gracefully, preventing a single failure from crashing our entire application.

The Core Structure: `try`, `catch`, and `finally`

This structure is the foundation of synchronous error handling in JavaScript.

  • `try`: You place your "risky" code inside this block. JavaScript will attempt to execute it.
  • `catch (error)`: This block is a safety net. It only executes if an error is "thrown" inside the `try` block. It receives an Error object containing details about the failure.
  • `finally`: This block is the cleanup crew. It always executes, regardless of whether the `try` block succeeded or the `catch` block was triggered. It's essential for releasing resources, like closing a file or a database connection.
try {
  // 1. Risky operation
  let data = riskyFunction();
} catch (error) {
  // 2. Runs ONLY if riskyFunction() throws an error
  console.error("An error occurred: " + error.message);
} finally {
  // 3. Runs ALWAYS, after try or catch
  console.log("Cleanup complete.");
}

Anatomy of the Error Object

When an error is caught, the `error` object provides vital information for debugging:

  • `error.name`: The type of error (e.g., `TypeError`, `ReferenceError`).
  • `error.message`: A human-readable description of the error.
  • `error.stack`: A "stack trace" showing the sequence of function calls that led to the error. This is often the most useful property for debugging.

Common Built-in Error Types

JavaScript has several built-in error types that it throws automatically:

`ReferenceError`

Thrown when you try to access a variable that hasn't been declared.

console.log(myUndeclaredVar);

`TypeError`

Thrown when an operation is performed on the wrong data type, like calling a non-function.

const num = 123;
num.toUpperCase();

`SyntaxError`

Thrown by the JavaScript engine when it encounters code that is not valid. This error cannot be caught by `try...catch`.

let x =;

`RangeError`

Thrown when a numeric value is outside its allowed range (e.g., invalid array length).

new Array(-1);

Creating Your Own Errors with `throw`

You don't have to wait for JavaScript to throw an error. You can create your own for business logic and validation using the `throw` keyword.

function setAge(age) {
  if (age < 0) {
    throw new Error("Age cannot be negative.");
  }
  this.age = age;
}

Advanced: Custom Error Classes

For large applications, you can create your own Error classes by extending the base `Error` class. This allows you to create specific error types and check for them in your `catch` block.

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

try {
  throw new ValidationError("Invalid email!");
} catch (error) {
  if (error instanceof ValidationError) {
    // Handle this specific error type
    showUserFriendlyError(error.message);
  } else {
    // Handle other unexpected errors
    logErrorToServer(error);
  }
}

The Asynchronous Challenge: Promises and `async/await`

`try...catch` only works for synchronous code or `async/await`. It will not catch errors from traditional Promise chains.

  • Promises (`.catch()`): For standard Promise chains, you must use the `.catch()` method to handle errors.
  • `async/await` (Recommended): This modern syntax allows you to handle asynchronous errors with the same `try...catch` block you use for synchronous code, making it much cleaner.

❌ Bad Practice

// THIS WILL NOT WORK
try {
  fetch('...')
    .then(res => res.json())
    .then(data => {...}); // Error here is not caught
} catch (e) {
  // This catch block will not run
}

✔️ Good Practice

async function getData() {
  try {
    const res = await fetch('...');
    const data = await res.json();
    return data;
  } catch (e) {
    // This WILL catch errors from fetch()
    console.error("Fetch failed:", e);
  }
}
Key Takeaway: Use `try...catch` to handle errors gracefully. Use `finally` for cleanup. Use `throw` to create your own errors. And always use `async/await` with `try...catch` to handle asynchronous errors in a clean, readable way.

JavaScript Error Glossary

try
A block of code that encloses statements that might throw an exception.
catch
A block of code that is executed if an exception is thrown in the `try` block. It receives the error object.
finally
A block of code that is executed after the `try` and `catch` blocks complete, regardless of whether an exception was thrown. Used for cleanup.
throw
A statement used to create a user-defined exception. It halts execution and passes control to the nearest `catch` block.
Error Object
An object passed to the `catch` block containing properties like `name`, `message`, and `stack`.
Stack Trace (`error.stack`)
A report of the function calls that led to the error, used for debugging.
ReferenceError
An error thrown when trying to access a variable that is not declared.
TypeError
An error thrown when a value is not of the expected type (e.g., calling a number as a function).
async / await
Modern syntax that allows asynchronous, promise-based code to be written as if it were synchronous, and enables `try...catch` to handle async errors.
Promise `.catch()`
The traditional method for handling errors in a Promise chain, used when not using `async/await`.

About the Author

Author's Avatar

TodoTutorial Team

Passionate developers and educators making programming accessible to everyone.

This article was written and reviewed by our team of senior JavaScript developers, who have extensive experience in building large-scale, resilient web applications.

Verification and Updates

Last reviewed: October 2025.

We strive to keep our content accurate. This tutorial reflects the latest ECMAScript (ES2025) standards for error handling, including best practices for asynchronous operations.

External Resources

Found an error or have a suggestion? Contact us!