Express requires error-handling middleware to have exactly four parameters: (err, req, res, next). Without all four parameters, Express treats the function as regular middleware instead of an error handler. This error occurs when your error handler doesn't follow the correct signature.
Express distinguishes error-handling middleware from regular middleware by the number of function parameters. Error handlers must accept exactly four arguments in the correct order: the error object, request object, response object, and next function. If your middleware function has fewer parameters or they're in the wrong order, Express won't recognize it as an error handler and won't execute it when errors occur. This is a design constraint built into Express to maintain a clear separation between normal request processing and error handling.
Check that your error-handling middleware function accepts all four parameters in the correct order:
// CORRECT - 4 parameters
app.use((err, req, res, next) => {
res.status(err.status || 500).send(err.message);
});
// WRONG - only 3 parameters (treated as regular middleware)
app.use((req, res, next) => {
res.status(500).send('Error');
});Express identifies error-handling middleware by counting the number of function parameters. You must have all four, even if you don't use all of them.
The parameter order must be: err, req, res, next.
// CORRECT order
app.use((err, req, res, next) => {
console.error(err.message);
res.status(500).json({ error: 'Internal Server Error' });
});
// WRONG - parameters in wrong order
app.use((req, res, err, next) => {
// This won't work as error handler
});The error object must be the first parameter for Express to recognize this as an error handler.
Error-handling middleware must be defined after all other routes and middleware:
const express = require('express');
const app = express();
// Regular middleware and routes FIRST
app.use(express.json());
app.get('/api/data', (req, res) => {
throw new Error('Something went wrong');
});
// Error handler LAST
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
message: err.message,
error: process.env.NODE_ENV === 'production' ? {} : err,
});
});
app.listen(3000);If you define the error handler before your routes, it won't catch errors thrown in those routes.
Your error handler must always send a response or call next(err). Failing to do so will cause requests to hang:
app.use((err, req, res, next) => {
// GOOD - send a response
res.status(err.status || 500).json({ error: err.message });
// OR call next to pass to another error handler
// next(err);
// BAD - neither send nor call next (request hangs)
// console.error(err);
});Always ensure one of these paths is taken for every error.
Create a simple test to verify your error handler works:
const express = require('express');
const app = express();
// Test route that throws an error
app.get('/test-error', (req, res) => {
throw new Error('Test error message');
});
// Error handler with 4 parameters
app.use((err, req, res, next) => {
console.log('Error caught:', err.message);
res.status(500).json({ error: err.message });
});
app.listen(3000, () => console.log('Server running'));Visit http://localhost:3000/test-error and verify the error handler catches the thrown error.
In async route handlers and middleware, remember that thrown errors won't automatically be caught by Express error handlers. You must use try-catch blocks or .catch() chains:
// Using try-catch with async
app.get('/async-route', async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (err) {
next(err); // Pass to error handler
}
});
// Or wrap with a utility
const asyncHandler = (fn) => (req, res, next) => {
Promise.resolve(fn(req, res, next)).catch(next);
};
app.get('/route', asyncHandler(async (req, res) => {
const data = await fetchData();
res.json(data);
}));Typescript developers should type the error handler properly:
import { Express, Request, Response, NextFunction } from 'express';
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
res.status(500).json({ message: err.message });
});Error: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process