Errors Crash Servers
Unhandled errors in Node.js kill the process.
Async/Await Error Handling
async function getUser(id) {
try {
const user = await db.users.findById(id);
if (!user) {
throw new NotFoundError('User not found');
}
return user;
} catch (error) {
logger.error('Failed to get user', { id, error });
throw error;
}
}
Custom Error Classes
class AppError extends Error {
constructor(message, statusCode = 500) {
super(message);
this.statusCode = statusCode;
this.isOperational = true;
}
}
class NotFoundError extends AppError {
constructor(message = 'Not found') {
super(message, 404);
}
}
class ValidationError extends AppError {
constructor(message, errors = []) {
super(message, 422);
this.errors = errors;
}
}
Centralized Error Handler
// Express middleware
function errorHandler(err, req, res, next) {
logger.error(err);
if (err.isOperational) {
return res.status(err.statusCode).json({
error: {
message: err.message,
...(err.errors && { errors: err.errors })
}
});
}
// Unknown error - don't leak details
res.status(500).json({
error: { message: 'Internal server error' }
});
}
app.use(errorHandler);
Catch Unhandled Rejections
process.on('unhandledRejection', (reason, promise) => {
logger.error('Unhandled Rejection:', reason);
// In production, you might want to exit and let process manager restart
});
process.on('uncaughtException', (error) => {
logger.error('Uncaught Exception:', error);
process.exit(1); // Exit - state is uncertain
});
Async Route Wrapper
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Usage
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await getUser(req.params.id);
res.json(user);
}));
