Skip to content
5 min read

JavaScript Error Handling: try, catch, and finally

Learn JavaScript error handling with try, catch, and finally. This guide covers catching runtime errors, throwing custom errors, handling async errors, and avoiding silent failures.

#javascript #errorhandling #frontend #beginner

JavaScript error handling separates code that works in demos from code that works in production. Errors happen — network requests fail, data is missing, functions receive unexpected input. Knowing how to handle them gracefully is essential for any JavaScript developer.

The try/catch Block

Wrap code that might throw an error in try. If an error occurs, execution jumps to catch:

try {
  const data = JSON.parse("this is not valid JSON");
} catch (error) {
  console.error("Parsing failed:", error.message);
}

Without the try/catch, the invalid JSON parse would crash your script. With it, you handle the error and continue.

The Error Object

The error in catch (error) is an Error object with useful properties:

try {
  null.property; // TypeError
} catch (error) {
  console.log(error.name);    // "TypeError"
  console.log(error.message); // "Cannot read properties of null"
  console.log(error.stack);   // Full stack trace
}

Throwing Custom Errors

You can throw errors intentionally to signal invalid states:

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.error(error.message);
}

For complex apps, create custom error classes:

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

throw new ValidationError("email", "Invalid email format");

Error Handling with async/await

async function fetchUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`);
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error("Failed to fetch user:", error.message);
    return null;
  }
}

The finally Block

finally runs whether or not an error occurred — perfect for cleanup:

let connection;
try {
  connection = await openDatabaseConnection();
  await runQuery(connection);
} catch (error) {
  console.error(error);
} finally {
  if (connection) connection.close(); // Always closes the connection
}

Conclusion

Good JavaScript error handling means your app fails gracefully instead of silently or catastrophically. Use try/catch for anything that can throw, always handle async errors, use finally for cleanup, and throw meaningful errors with clear messages. Your users — and future you — will appreciate it.

Read next: async/await in JavaScript

External resource: MDN — Error Handling Statements

Kaikobud Sarkar

Kaikobud Sarkar

Software engineer passionate about backend technologies and continuous learning. I write about Python frameworks, cloud architecture, engineering growth, and staying current in tech.

Related Articles

How to Write Clean Functions in JavaScript

Learn how to write clean JavaScript functions that are easy to read, test, and maintain. This guide covers naming, single responsibility, pure functions, and avoiding common pitfalls.

#javascript #bestpractices

CSS Flexbox in Plain English: A Beginner's Guide

Learn CSS Flexbox with simple, visual explanations. This guide covers display flex, justify-content, align-items, flex-wrap, and practical layouts every developer needs to know.

#css #flexbox