Skip to content

Exception Handling in JavaScript

In JavaScript, exceptions are handled using try...catch blocks. This allows you to gracefully handle errors that occur during execution rather than having the script fail completely.

try {
// Code that may throw an error
} catch (error) {
// Code to handle the error
} finally {
// Optional code that runs regardless of success or failure
}

How to Create Custom Exceptions in JavaScript

Section titled “How to Create Custom Exceptions in JavaScript”

You can create custom exception classes by extending JavaScript’s built-in Error class. This allows you to add custom properties like error codes and additional details, making your error handling more informative and structured.

The following example shows a CustomError class that accepts a message, an error code, and a details object for storing custom data. The class extends Error and uses the super() method to initialize the parent class while adding custom properties.

/**
* Custom error class that extends the built-in `Error` class.
* It includes additional properties such as a custom error code and details.
* This allows for more context when handling errors.
*
* @class
* @extends {Error}
*/
class CustomError extends Error {
/**
* Creates an instance of CustomError.
*
* @param {string} message - The error message.
* @param {string|number} code - A custom error code to help identify the type of error.
* @param {Object} [details] - Optional additional context or details about the error.
*/
constructor(message, code, details) {
super(message); // Call the parent constructor with the message
this.name = this.constructor.name; // Set the error name to CustomError
this.code = code; // Custom error code
this.details = details; // Additional details or context
// Optional: Ensure the stack trace is correct for this subclass
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
}

You can create more specific error classes by extending CustomError. This is useful for handling different error scenarios:

class NotFoundError extends CustomError {
constructor(message, details) {
super(message, 404, details);
}
}
class ValidationError extends CustomError {
constructor(message, details) {
super(message, 400, details);
}
}

Once you’ve created a custom exception class, you can throw instances of it with specific data:

try {
throw new CustomError("Invalid user input", 400, { field: "username", expected: "non-empty" });
} catch (error) {
if (error instanceof CustomError) {
console.log("CustomError caught!");
console.log(`Message: ${error.message} (Code: ${error.code})`);
console.log("Details:", error.details);
} else {
console.error("An unknown error occurred:", error);
}
}

When dealing with multiple error types, chain instanceof checks to handle each one specifically:

try {
// Your code here...
} catch (error) {
if (error instanceof ValidationError) {
console.log(`Validation error: ${error.message} (Code: ${error.code})`);
console.log("Details:", error.details);
} else if (error instanceof NotFoundError) {
console.log(`Not found: ${error.message} (Code: ${error.code})`);
console.log("Details:", error.details);
} else if (error instanceof CustomError) {
console.log(`Unexpected error: ${error.message} (Code: ${error.code})`);
} else {
console.error("Unknown error type:", error);
}
}