Error handling is crucial for building reliable Express applications. Without proper error handling, unhandled promise rejections and thrown errors can crash your Node.js server, leading to poor user experience and system instability.
Express provides a built-in error handling mechanism, but it requires following specific patterns. Express error handlers are special middleware functions that accept four parameters: (err, req, res, next). When an error occurs in your application, Express will skip all regular middleware and route handlers, jumping directly to error handling middleware.
The challenge with async route handlers is that Express doesn't automatically catch promise rejections. If an async function throws an error or returns a rejected promise, Express won't catch it unless you explicitly handle it. This is where async wrappers become essential.
Custom error classes extend the built-in Error object to provide additional context. By creating an AppError class with properties like statusCode and isOperational, you can distinguish between expected errors (like "user not found") and unexpected programming bugs. This distinction is valuable for logging, monitoring, and deciding whether to expose error details to clients.
The three-layer approach—custom error classes, async wrappers, and global error handlers—creates a robust system. Custom errors provide structure, async wrappers ensure all errors are caught, and global handlers provide consistent error responses across your entire application.
1// Custom error class
2class ValidationError extends Error {
3 constructor(message, field) {
4 super(message);
5 this.field = field;
6 this.statusCode = 400;
7 }
8}
9
10// Async wrapper function
11const catchAsync = (fn) => {
12 return (req, res, next) => {
13 Promise.resolve(fn(req, res, next)).catch(next);
14 };
15};
16
17// Usage in routes
18app.get('/profile', catchAsync(async (req, res) => {
19 const user = await User.findById(req.params.id);
20 if (!user.email) {
21 throw new ValidationError('Email is required', 'email');
22 }
23 res.json(user);
24}));