Skip to main content

Command Palette

Search for a command to run...

Error Handling in JavaScript: Try, Catch, Finally

Updated
โ€ข8 min read
Error Handling in JavaScript: Try, Catch, Finally

What errors are in JavaScript

In JavaScript, errors are problems that occur when your code doesnโ€™t run correctly. Understanding them helps you debug faster and write better code.


๐Ÿ”น 1. Syntax Errors

๐Ÿ‘‰ Mistakes in code structure (grammar of JS)

Example:

console.log("Hello"

โŒ Missing ) โ†’ code wonโ€™t run at all


๐Ÿ”น 2. Reference Errors

๐Ÿ‘‰ Using a variable that is not declared

Example:

console.log(x);

โŒ x is not defined


๐Ÿ”น 3. Type Errors

๐Ÿ‘‰ Performing operation on wrong data type

Example:

let num = 10;
num.toUpperCase();

โŒ Numbers donโ€™t have toUpperCase()


๐Ÿ”น 4. Range Errors

๐Ÿ‘‰ Value is out of allowed range

Example:

let arr = new Array(-1);

โŒ Invalid array length


๐Ÿ”น 5. Logical Errors

๐Ÿ‘‰ Code runs but gives wrong output

Example:

let a = 10, b = 5;
console.log(a - b); // expected addition?

๐Ÿ‘‰ No error shown, but wrong logic


๐Ÿ”น 6. Runtime Errors

๐Ÿ‘‰ Errors that occur while code is running

Example:

let obj = null;
console.log(obj.name);

โŒ Cannot read properties of null


๐Ÿ”น 7. URI Errors

๐Ÿ‘‰ Issues with URL encoding/decoding

Example:

decodeURIComponent("%");

โŒ Invalid URI sequence


๐Ÿ”น 8. Eval Error (Rare)

๐Ÿ‘‰ Related to misuse of eval() (rarely used now)


๐Ÿ”น Error Handling in JS

Try-Catch Example:

try {
  console.log(x);
} catch (error) {
  console.log("Error:", error.message);
}

๐Ÿ”น Custom Error

throw new Error("Something went wrong");

Using try and catch blocks

When you write code, errors are inevitable. The key isnโ€™t avoiding them entirelyโ€”itโ€™s handling them gracefully so your application doesnโ€™t crash. Thatโ€™s where try...catch comes in.


๐Ÿ”น What is try...catch?

In JavaScript, try...catch is used to handle runtime errors. It allows your program to continue running even if something goes wrong.


๐Ÿ”น Basic Syntax

try {
  // Code that might throw an error
} catch (error) {
  // Code to handle the error
}
  • try โ†’ contains code that may fail

  • catch โ†’ runs if an error occurs


๐Ÿ”น Simple Example

try {
  console.log(userName); // variable not defined
} catch (error) {
  console.log("Something went wrong:", error.message);
}

๐Ÿ‘‰ Instead of crashing, the program handles the error smoothly.


๐Ÿ”น Why Use try...catch?

  • Prevents application crashes

  • Improves user experience

  • Helps in debugging

  • Allows fallback logic


๐Ÿ”น The finally Block

The finally block runs no matter whatโ€”whether an error occurs or not.

try {
  console.log("Trying...");
} catch (e) {
  console.log("Error occurred");
} finally {
  console.log("This always runs");
}

๐Ÿ”น Throwing Custom Errors

You can create your own errors using throw.

function withdraw(amount) {
  if (amount > 1000) {
    throw new Error("Insufficient balance");
  }
  return "Transaction successful";
}

try {
  withdraw(1500);
} catch (e) {
  console.log(e.message);
}

๐Ÿ”น Real-World Use Case

Handling invalid JSON data:

try {
  let data = JSON.parse('invalid json');
} catch (e) {
  console.log("Invalid JSON format");
}

๐Ÿ‘‰ Useful when working with APIs or external data.


๐Ÿ”น Important Points

  • try...catch only handles runtime errors

  • It does NOT catch syntax errors

  • Use it where errors are expected (e.g., API calls, parsing data)


๐Ÿ”น Best Practices

  • Donโ€™t overuse try...catch everywhere

  • Keep try blocks small

  • Always log or handle errors properly

  • Use meaningful error messages


๐Ÿ”น Conclusion

Error handling is a crucial part of writing robust JavaScript code. By using try...catch, you ensure your application behaves reliablyโ€”even when things go wrong.


The finally block

In JavaScript, the finally block is a component of the try...catch...finally statement used for guaranteed code execution.

Key Characteristics

  • Guaranteed Execution: The code inside a finally block runs regardless of whether an error was thrown in the try block or caught in the catch block.

  • Control Flow Persistence: Even if a return, throw, break, or continue statement is executed within the try or catch blocks, the finally block will still execute before the function actually returns or the error propagates.

  • Optional Usage: You can use try...finally without a catch block if you want to ensure cleanup but allow errors to propagate to a higher scope.

  • Common Use Cases

    The finally block is primarily used for cleanup tasks that must happen no matter the outcome of the preceding operations:

  • Closing Resources: Disconnecting from a database or closing a file stream.

  • UI Resets: Hiding a loading spinner or enabling a button after an asynchronous API call.

  • State Management: Clearing temporary variables or resetting timers.

Basic Syntax

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

Throwing custom errors

When building applications, sometimes built-in errors arenโ€™t enough. You may want to define your own rules and throw errors when those rules are violated. This is where custom errors come in.


๐Ÿ”น What are Custom Errors?

Custom errors are user-defined errors created using the throw keyword. They help you:

  • Validate inputs

  • Enforce business rules

  • Provide meaningful error messages


๐Ÿ”น Basic Syntax

throw new Error("Something went wrong");

๐Ÿ‘‰ This immediately stops execution and sends control to the nearest catch block.


๐Ÿ”น Simple Example

function withdraw(amount) {
  if (amount > 5000) {
    throw new Error("Withdrawal limit exceeded");
  }
  return "Transaction successful";
}

try {
  withdraw(6000);
} catch (error) {
  console.log(error.message);
}

๐Ÿ‘‰ Output: Withdrawal limit exceeded


๐Ÿ”น Why Use Custom Errors?

  • Makes debugging easier

  • Improves code readability

  • Helps handle specific conditions

  • Gives clear feedback to users


๐Ÿ”น Using Different Error Types

JavaScript provides built-in error constructors:

throw new TypeError("Invalid type");
throw new RangeError("Out of range");

๐Ÿ‘‰ Use them when appropriate for better clarity.


๐Ÿ”น Creating a Custom Error Class (Advanced)

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

function registerUser(age) {
  if (age < 18) {
    throw new ValidationError("User must be 18+");
  }
}

try {
  registerUser(16);
} catch (e) {
  console.log(e.name + ": " + e.message);
}

๐Ÿ‘‰ Output: ValidationError: User must be 18+


๐Ÿ”น Real-World Use Case

function login(password) {
  if (password.length < 6) {
    throw new Error("Password must be at least 6 characters");
  }
  return "Login successful";
}

๐Ÿ‘‰ Ensures proper input validation


๐Ÿ”น Best Practices

  • Use meaningful error messages

  • Choose correct error types

  • Donโ€™t overuse custom errors

  • Always handle errors using try...catch


๐Ÿ”น Conclusion

Custom errors give you control over how your program reacts to unexpected situations. By using throw, you can:

  • Enforce rules

  • Improve debugging

  • Build more reliable applications


Why error handling matters

Error handling in JavaScript is critical because it ensures applications remain functional and secure even when unexpected issues occur. Without it, a single runtime error can halt the entire script, leading to broken features or complete application crashes.

Key reasons why error handling matters:

  • Preventing Application Crashes: It allows programs to detect and manage anomalies during execution, preventing a complete shutdown and ensuring system stability.

  • Graceful Degradation: Instead of a "blank white screen," developers can provide meaningful feedback or fallback UI to guide users on what happened and how to proceed.

  • Faster Debugging: Proper handling involves capturing error objects that contain stack traces and descriptive messages, making it significantly easier to identify and fix bugs.

  • Security Protection: Handling errors internally prevents the system from leaking sensitive technical details, such as database schemas or file paths, which could be exploited by malicious actors.

  • Data Integrity: It safeguards against data loss or corruption that might occur if an operation fails halfway through without a controlled recovery path.

  • Resilience in Asynchronous Code: In modern JavaScript, handling errors in async/await or Promises is essential for managing network timeouts, unreachable servers, or invalid API responses.