Topic 45 of 55
Express Error Handling Middleware
Overview
Express has a special type of middleware for handling errors. If you pass an argument to `next(err)`, Express skips all regular middleware and routes, going straight to the next error-handling middleware.
Syntax
javascript
app.get('/files', (req, res, next) => {
const fs = require('fs');
fs.readFile('/does-not-exist.txt', (err, data) => {
if (err) {
// Passing an error to next() triggers the Error Handler
return next(err);
}
res.send(data);
});
});
// Error-Handling Middleware MUST have exactly 4 arguments: (err, req, res, next)
// It must be defined AFTER all your other app.use() and routes!
app.use((err, req, res, next) => {
console.error("Global Error Catcher:", err.stack);
// Don't leak server details to the client in production
const statusCode = err.status || 500;
res.status(statusCode).json({
error: "Something went wrong!",
message: process.env.NODE_ENV === 'development' ? err.message : undefined
});
});Common Pitfalls
- If your error middleware has only 3 arguments `(err, req, res)`, Express treats it as regular middleware, NOT an error handler, and it will break.
- In Express 5 (currently in beta/RC), async error handling is built-in, meaning the `asyncHandler` wrapper pattern will no longer be necessary.
Real-World Example
Handling asynchronous errors cleanly using a wrapper function:
example
javascript
// Express 4 doesn't catch errors thrown in 'async' functions automatically.
// You have to wrap them in try/catch and call next(err).
// A cleaner way is an async wrapper:
const asyncHandler = fn => (req, res, next) => {
return Promise
.resolve(fn(req, res, next))
.catch(next); // Automatically passes caught errors to next()
};
// Now you don't need try/catch blocks!
app.get('/users', asyncHandler(async (req, res) => {
const users = await db.getUsers(); // If this throws, it goes to the error handler
res.json(users);
}));