Custom Error classes
Defines new error types by extending the built-in `Error` class, allowing for more specific error handling and identification.
class CustomError extends Error { constructor(message, options) { super(message, options); this.name = 'CustomError'; // Best practice } }This static page keeps the syntax and examples indexed for search, while the coding app handles interactive exploration and saved references.
What it does
Overview
Defines new error types by extending the built-in `Error` class, allowing for more specific error handling and identification.
Custom error classes provide a powerful way to create domain-specific error types, making error handling in applications more robust, semantic, and maintainable. By extending the built-in `Error` class (e.g., `class ValidationError extends Error`), your custom errors automatically inherit essential properties like `message` and `stack`, which are crucial for debugging. The primary benefit of custom errors is that you can use `instanceof` to identify specific error types in your `catch` blocks, allowing for differentiated error handling logic. For example, you might handle a `NetworkError` by retrying the request, a `ValidationError` by displaying specific form feedback, and a generic `Error` by logging it and showing an 'unexpected error' message. When creating a custom error class, it's a best practice to call `super(message, options)` in the constructor to correctly initialize the `Error` base class and to explicitly set `this.name` to the class name (e.g., `this.name = 'ValidationError'`) for better stack trace readability and consistency across environments. Custom errors significantly improve code clarity, enable more precise error recovery strategies, and enhance the overall developer experience in complex applications.
Quick reference
Syntax
class CustomError extends Error { constructor(message, options) { super(message, options); this.name = 'CustomError'; // Best practice } }
See it in practice
Examples
Basic custom error class
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
function validateInput(value) {
if (!value || value.length < 5) {
throw new ValidationError('Input must be at least 5 characters long.');
}
return true;
}
try {
validateInput('abc');
} catch (error) {
if (error instanceof ValidationError) {
console.error(`Validation Failed: ${error.message}`);
} else {
console.error(`An unexpected error occurred: ${error.message}`);
}
}Validation Failed: Input must be at least 5 characters long.
A `ValidationError` class extends `Error`. The `catch` block uses `instanceof` to specifically identify and handle validation errors, demonstrating type-based error handling.
Custom error with additional properties
class NetworkError extends Error {
constructor(message, statusCode) {
super(message);
this.name = 'NetworkError';
this.statusCode = statusCode;
}
}
async function fetchData(url) {
const response = await fetch(url);
if (!response.ok) {
throw new NetworkError(`Failed to fetch ${url}`, response.status);
}
return response.json();
}
async function runFetch() {
try {
await fetchData('https://nonexistent.api/data');
} catch (error) {
if (error instanceof NetworkError) {
console.error(`Network Error (${error.statusCode}): ${error.message}`);
// Specific handling for network issues, e.g., retry logic
} else {
console.error(`Generic Error: ${error.message}`);
}
}
}
runFetch();Network Error (404): Failed to fetch https://nonexistent.api/data
The `NetworkError` includes a `statusCode` property, providing more context. The `catch` block can then access this property for more granular error handling or logging.
Chaining custom errors with `Error.cause`
class DatabaseError extends Error {
constructor(message, options) {
super(message, options);
this.name = 'DatabaseError';
}
}
class DataProcessingError extends Error {
constructor(message, options) {
super(message, options);
this.name = 'DataProcessingError';
}
}
function saveToDb(data) {
try {
// Simulate a database operation that fails
throw new Error('Connection refused by DB server.');
} catch (dbErr) {
throw new DatabaseError('Could not save data to database.', { cause: dbErr });
}
}
function processAndSave(payload) {
try {
// Simulate data processing logic
if (!payload.isValid) {
throw new Error('Payload is invalid.');
}
saveToDb(payload);
} catch (procErr) {
throw new DataProcessingError('Failed to process and save payload.', { cause: procErr });
}
}
try {
processAndSave({ isValid: false });
} catch (finalError) {
console.error(`Top-level Error: ${finalError.name}: ${finalError.message}`);
let current = finalError;
while (current.cause) {
current = current.cause;
console.error(` Caused by: ${current.name || 'Error'}: ${current.message}`);
}
}Top-level Error: DataProcessingError: Failed to process and save payload. Caused by: Error: Payload is invalid.
This demonstrates chaining custom errors. A `DataProcessingError` wraps a generic `Error`, and if `saveToDb` were to fail, a `DatabaseError` would wrap that. The top-level catch can then traverse the `cause` chain.
Debug faster
Common Errors
Forgetting to call `super()` in the constructor
Cause: If `super()` is not called in the constructor of a custom error class, `this` will not be initialized, leading to a `ReferenceError` or incorrect behavior of the inherited `Error` properties (like `stack`).
Fix: Always call `super(message, options)` as the first statement in your custom error class constructor to properly initialize the base `Error` class.
class MyError extends Error {
constructor(message) {
// super(message); // Missing call to super()
this.name = 'MyError';
}
}
try {
throw new MyError('Test');
} catch (e) {
// ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
}Runtime support
Compatibility
Source: MDN Web Docs
Common questions
Frequently Asked Questions
Defines new error types by extending the built-in `Error` class, allowing for more specific error handling and identification.
Forgetting to call `super()` in the constructor: Always call `super(message, options)` as the first statement in your custom error class constructor to properly initialize the base `Error` class.