Error Handling Express
title: "Error Handling in Express — Building Robust Middleware Stacks" description: "Error handling in Express.js uses centralized error middleware to catch exceptions, return consistent responses, and log errors with trace IDs." date: 2026-06-28 lastmod: 2026-06-28 weight: 29 tags: [apis, error-handling] }
Express error handling uses specialized four-argument middleware functions to catch errors from all routes and return consistent, structured JSON error responses.
What You'll Learn
- Express error middleware patterns
- Handling sync and async errors
- Custom error classes
Why It Matters
Express doesn't catch async errors by default. Without proper setup, unhandled promise rejections crash the server.
Code Examples
// Express error handling setup
const express = require('express');
const app = express();
// Async error wrapper
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
// Custom error class
class AppError extends Error {
constructor(message, statusCode = 400, code = null) {
super(message);
this.statusCode = statusCode;
this.code = code || 'APP_ERROR';
this.isOperational = true;
}
}
// Async route with error handling
app.get('/users/:id', asyncHandler(async (req, res) => {
const user = await db.findUser(req.params.id);
if (!user) {
throw new AppError('User not found', 404, 'USER_NOT_FOUND');
}
res.json(user);
}));
// 404 catch-all
app.use((req, res) => {
res.status(404).json({
error: 'NOT_FOUND',
message: `Route ${req.method} ${req.path} not found`
});
});
// Central error handler
app.use((err, req, res, next) => {
const traceId = uuidv4();
const statusCode = err.statusCode || 500;
const code = err.code || 'INTERNAL_ERROR';
console.error(`[${traceId}]`, err.stack);
res.status(statusCode).json({
error: code,
message: err.isOperational ? err.message : 'An unexpected error occurred',
trace_id: traceId
});
});
Common Mistakes
1. Not Wrapping Async Routes
Express 4 doesn't catch async errors. Always wrap async handlers.
2. Error Middleware Not Last
Error middleware must be the last middleware registered.
3. Not Differentiating Operational vs Programming Errors
Operational errors (validation) are safe to report; programming errors should be generic.
4. Missing 404 Catch-All
Without a 404 handler, unmatched routes return HTML or nothing.
5. Not Exiting on Uncaught Errors
Use process.on('uncaughtException') and process.on('unhandledRejection') for safety.
Practice Questions
- How many arguments does Express error middleware take?
- Why must async routes be wrapped?
- What is the difference between operational and programming errors?
- Where should error middleware be placed in the middleware stack?
- How do you handle uncaught exceptions in Node.js?
Answers:
- Four: (err, req, res, next).
- Express doesn't catch promise rejections from async functions.
- Operational errors are expected (validation); programming errors are bugs (undefined).
- Last, after all routes and other middleware.
- With
process.on('uncaughtException')andprocess.on('unhandledRejection')handlers.
Challenge: Build a complete Express error handling system with async wrappers, custom error classes, 404 handler, centralized error middleware, and process-level exception handlers.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro