handler-error v2.7.0
Want to write error messages that truly help developers?
Check out this article where we explain best practices for creating useful error messages. This library is designed to follow those principles!
AI Assistant for Better Error Messages
I have developed a GPT-based assistant that follows these guidelines to help you write better error messages. You can access it here!
✨ Features
- Custom Error Class: HandlerError to encapsulate detailed error information, including severity, metadata, and causation.
- Flexible Constructor: Create errors with a message, code, metadata, and cause.
- Severity Levels: Assign severity levels to errors for better handling and logging.
📦 Installation
# Install with npm:
npm install handler-error
# Install with yarn:
yarn add handler-error
# Install with pnpm:
pnpm add handler-error
🚀 Getting Started
Basic Usage
import { HandlerError } from "handler-error";
try {
throw new HandlerError("Something went wrong");
} catch (error) {
console.error(error.serialize());
}
Custom errors class (recommended)
To create a custom error class, extend the HandlerError
class and pass the arguments to the parent constructor.
Create a custom error class.
import { HandlerError } from "handler-error"; class AppError extends HandlerError { constructor(...arguments_) { super(...arguments_); } }
Type guard to check if an error is an instance of
AppError
.function isAppError(error: Error): error is AppError { return error instanceof AppError; }
Catch and handle the custom error.
try { throw new AppError("Something went wrong"); } catch (error) { if (isAppError(error)) { console.error(error.serialize()); } }
Handling errors with a custom handler
function handleError(error: Error) {
if (error instanceof AppError) {
console.error("AppError:", error.serialize());
} else {
console.error("Unknown error:", error.message);
}
}
try {
throw new AppError("Something went wrong");
} catch (error) {
handleError(error);
}
📖 API Reference
Flexible Error Creation
The HandlerError class provides a highly flexible constructor that adapts to different scenarios. You can include additional metadata, specify an error code, or link to a cause.
The constructor accepts the following arguments:
message
(required): A message describing the error.code
(optional): A custom error code.metadata
(optional): Additional information to provide context for the error.cause
(optional): The cause of the error.
You must maintain the order of the arguments to ensure correct behavior. However, any optional argument can be omitted without passing undefined, resulting in a more elegant and intuitive constructor design.
import { HandlerError } from "handler-error";
// Create a simple error with a message.
const error = new HandlerError("Something went wrong");
// Create an error with a custom code.
const error = new HandlerError("Something went wrong", "ERR_CUSTOM");
// Create an error with additional metadata.
const metadata = { user: "John Doe" };
const error = new HandlerError("Something went wrong", metadata);
// Create an error with a cause.
const cause = new HandlerError("Internal error");
const error = new HandlerError("Something went wrong", cause);
// Create an error with a custom code and cause.
const cause = new HandlerError("Internal error");
const error = new HandlerError("Something went wrong", "ERR_CUSTOM", cause);
// Create an error with metadata and a cause.
const metadata = { user: "John Doe" };
const cause = new HandlerError("Internal error");
const error = new HandlerError("Something went wrong", metadata, cause);
// Create an error with all arguments.
const metadata = { user: "John Doe" };
const cause = new HandlerError("Internal error");
const error = new HandlerError("Something went wrong", "ERR_CUSTOM", metadata, cause);
CodeHandlerError
The CodeHandlerError class extends the base HandlerError class and integrates with the ErrorCatalog module to provide centralized error management. It allows you to define errors using a predefined error code from the catalog, automatically retrieving associated metadata such as messages and severity.
the CodeHandlerError class requires an error code as the first argument. This code is used to retrieve the error message and severity from the catalog. You can also include a message as the second argument to override the default message.
Note: If the provided error code is not found in the catalog, CodeHandlerError will throw an error. Ensure all error codes are registered in the ErrorCatalog before use.
All API methods and properties from the HandlerError class are available in the CodeHandlerError class.
import { CodeHandlerError } from "handler-error";
// Create an error with a predefined error code.
const error = new CodeHandlerError("VAL_001");
// Create an error with a custom message.
const error = new CodeHandlerError("VAL_001", "Custom message");
// Create an error with additional metadata.
const metadata = { user: "John Doe" };
const error = new CodeHandlerError("VAL_001", metadata);
// Create an error with a cause.
const cause = new CodeHandlerError("VAL_002");
const error = new CodeHandlerError("VAL_001", cause);
// Create an error with a custom message and cause.
const cause = new CodeHandlerError("VAL_002");
const error = new CodeHandlerError("VAL_001", "Custom message", cause);
// Create an error with metadata and a cause.
const metadata = { user: "John Doe" };
const cause = new CodeHandlerError("VAL_002");
const error = new CodeHandlerError("VAL_001", metadata, cause);
// Create an error with all arguments.
const metadata = { user: "John Doe" };
const cause = new CodeHandlerError("VAL_002");
const error = new CodeHandlerError("VAL_001", "Custom message", metadata, cause);
Properties
Property | Type | Description |
---|---|---|
id | string | Unique identifier for the error. |
cause | HandlerError | The cause of the error. |
code | string | Custom error code for identifying the error. |
message | string | Message describing the error. |
metadata | object | Additional information to provide context for the error. |
name | string | Name of the error class. |
severity | Severity | Severity level of the error: critical , error , warning , info , debug . |
timestamp | Date | Timestamp of when the error curred. |
Methods
Method | Description | Return Value |
---|---|---|
serialize | Serialize the error to a plain object. | SerializedError |
toString | Returns a human-readable string representation of the error. | string |
Severity Levels
The HandlerError library supports the following severity levels:
Level | Usage |
---|---|
critical | For errors that require immediate attention and system shutdown |
error | For standard errors that prevent normal operation |
warning | For non-critical issues that don't prevent operation |
info | For informational messages about error handling |
debug | For detailed debugging information |
Using Severity Levels
The library provides static methods to create errors with specific severity levels. This simplifies error creation and ensures consistency
Note: The severity level is set to
error
by default.
import { HandlerError } from "handler-error";
// Add type information
const criticalError: HandlerError = HandlerError.critical(
"Database connection failed",
"DB_001",
{ attemptCount: 3 },
new Error("Connection timeout"),
);
// Add practical examples for each severity
const dbError = HandlerError.critical("Database connection failed"); // System cannot function
const authError = HandlerError.error("Invalid credentials"); // Operation failed
const rateLimit = HandlerError.warning("Rate limit at 80%"); // Potential issue
const configLoad = HandlerError.info("Using fallback config"); // Important information
const queryTime = HandlerError.debug("Query took 1.2s"); // Performance tracking
📚 Modules
Handling Error Chains
The ErrorChain
module provides utilities to work with chains of errors caused by one another. It allows you to trace, analyze, and process errors in a hierarchy.
This module makes it easy to trace and analyze errors in complex systems, ensuring you can track their causes and severity efficiently.
Method | Description | Return Value |
---|---|---|
getErrorChain | Get the full chain of errors starting from a specific error. | HandlerError[] |
getRootCause | Retrieves the root error of the chain. | HandlerError , null |
mapErrors<T> | Applies a mapper function to each error in the chain. | T[] |
findMostSevere | Finds the most severe error in the chain. | HandlerError , null |
serializeChain | Serializes the entire chain into an array of plain objects. | SerializedError[] |
import { ErrorChain } from "handler-error";
const error = new HandlerError("Something went wrong", "VAL_001");
const cause = new HandlerError("Internal error", "VAL_002", undefined, error);
// Get the full chain of errors
const chain = ErrorChain.getErrorChain(cause);
console.log(chain.length); // Output: 2
// Get the root cause of the chain
const rootCause = ErrorChain.getRootCause(cause);
console.log(rootCause.message); // Output: Something went wrong
// Find the most severe error in the chain
const mostSevere = ErrorChain.findMostSevere(cause);
console.log(mostSevere.message); // Output: Something went wrong
// Serialize the entire chain
const serializedChain = ErrorChain.serializeChain(cause);
Error Catalog
The ErrorCatalog module provides a centralized registry for managing error codes and their associated metadata. It allows developers to define a catalog of errors and retrieve information such as error messages, severity levels, and additional context by using error codes.
Method | Description | Return Value |
---|---|---|
registerCatalog | Register a catalog of errors. | void |
clearCatalog | Clear the error catalog. | void |
getEntry | Retrieve the error entry for a specific error code. | ErrorCatalogEntry |
import { ErrorCatalog } from "handler-error";
import { ErrorSeverity } from "handler-error";
const catalog = {
VAL_001: { message: "Critical validation error", severity: ErrorSeverity.CRITICAL },
VAL_002: { message: "Validation warning", severity: ErrorSeverity.WARNING },
VAL_003: { message: "Informational message", severity: ErrorSeverity.INFO },
};
// Register the catalog
ErrorCatalog.registerCatalog(catalog);
// Retrieve an error entry
const entry = ErrorCatalog.getEntry("VAL_001");
console.log(entry.message); // Output: Critical validation error
console.log(entry.severity); // Output: critical
Using Dynamic Messages
The ErrorCatalog allows defining error messages with placeholders in the format {{ key }}, where key corresponds to a metadata property. These placeholders are replaced with the values provided when the error is created.
import { ErrorCatalog } from "handler-error";
import { ErrorSeverity } from "handler-error";
const catalog = {
VAL001: { message: "Validation error for user {{ user }}", severity: ErrorSeverity.ERROR },
};
// Register the catalog
ErrorCatalog.registerCatalog(catalog);
// Create an error with metadata
const error = new CodeHandlerError("VAL001", { user: "John Doe" });
console.log(error.message); // Output: Validation error for user John Doe
Error Code Conventions
We recommend following these conventions for error codes:
- Use uppercase letters and underscores (e.g.,
ERR_INVALID_INPUT
) - Start with a category prefix (e.g.,
VAL_
for validation errors) - Include a numeric identifier (e.g.,
DB_001
)
Example categories:
VAL_
: Validation errorsAUTH_
: Authentication errorsDB_
: Database errorsAPI_
: API-related errors
Error Formatter
The Error Formatter
module provides an extensible framework for formatting error messages and error chains. It allows you to define custom formats for displaying errors in different contexts, such as logs, user interfaces, or reports.
Basic Usage
import { ErrorFormatter } from "handler-error";
// Define a custom error formatter
class CustomErrorFormatter extends ErrorFormatter {
format(error: HandlerError): string {
return `${error.id}: ${error.message}`;
}
}
// Use the custom error formatter
const formatter = new CustomErrorFormatter();
const error = new HandlerError("Something went wrong");
console.log(formatter.format(error)); // Output: 1234: Something went wrong
Implementing Custom Formats with options
import { ErrorFormatter } from "handler-error";
// Define custom format options
interface CustomFormatOptions {
context: string;
}
// Define a custom error formatter
class CustomErrorFormatter extends ErrorFormatter<CustomFormatOptions> {
private defaultOptions: CustomFormatOptions = {
context: "production",
};
format(error: HandlerError): string {
return `${error.id}: ${error.message} (${this.defaultOptions.context})`;
}
}
// Use the custom error formatter with options
const formatter = new CustomErrorFormatter();
const error = new HandlerError("Something went wrong");
console.log(formatter.format(error, options)); // Output: 1234: Something went wrong (production)
Implementing Custom Formats with custom options
import { ErrorFormatter } from "handler-error";
// Define custom format options
interface CustomFormatOptions {
context: string;
}
// Define a custom error formatter
class CustomErrorFormatter extends ErrorFormatter<CustomFormatOptions> {
private defaultOptions: CustomFormatOptions = {
context: "production",
};
format(error: HandlerError, options?: CustomFormatOptions): string {
const customOptions = { ...this.defaultOptions, ...options };
return `${error.id}: ${error.message} (${customOptions.context})`;
}
}
// Use the custom error formatter with custom options
const formatter = new CustomErrorFormatter();
const error = new HandlerError("Something went wrong");
console.log(formatter.format(error, { context: "development" })); // Output: 1234: Something went wrong (development)
Using Error Formatters with default Error Chains
import { ErrorFormatter, HandlerError } from "handler-error";
// Define a custom error formatter
class CustomErrorFormatter extends ErrorFormatter {
format(error: HandlerError): string {
return `${error.id}: ${error.message}`;
}
}
// Use the custom error formatter
const formatter = new CustomErrorFormatter();
const error = new HandlerError("Something went wrong");
const cause = new HandlerError("Internal error", undefined, error);
// Get the full chain of errors
console.log(formatter.formatChain(cause));
// Output:
// 1234: Internal error
// 5678: Something went wrong
Using Error Formatters with Custom Error Chains
import { ErrorChain, ErrorFormatter, HandlerError } from "handler-error";
class CustomErrorFormatter extends ErrorFormatter {
format(error: HandlerError): string {
return `${error.id}: ${error.message}`;
}
override formatChain(error: HandlerError): string {
return ErrorChain.mapErrors(error, (item, index) => `${index}: ${item.message}`).join("\n");
}
}
// Use the custom error formatter
const formatter = new CustomErrorFormatter();
const error = new HandlerError("Something went wrong");
const cause = new HandlerError("Internal error", undefined, error);
// Get the full chain of errors
console.log(formatter.formatChain(cause));
// Output:
// 1: Internal error
// 2: Something went wrong
🤝 Contributions
I love collaboration! Here's how you can help improve Handler Error.
- Fork the repository.
- Create a feature branch:
git checkout -b feature/<your-feature>
. - Install dependencies:
npm install
. - Create a branch for your changes:
git checkout -b feature/<your-feature>
. - Make your changes.
- Add tests for your changes.
- Ensure tests pass:
npm test
. - Check code style:
npm run lint
. - Commit your changes with semantic messages:
git commit -am 'feat: add new feature'
. - Submit a pull request with your changes to the
main
branch of thefvena/handler-error
repository.
Note: Please follow our commit message convention and ensure documentation is updated for new features.
📜 License
Distributed under the MIT License. See LICENSE for more information.