Error Handling in Express 5
Express 5 finally handles async route handlers properly: if an async handler throws or returns a rejected promise, the error goes to your error middleware. No more express-async-errors or wrapping every route in try/catch.
Async handlers just work
app.get('/users/:id', async (req, res) => {
const user = await db.users.find(req.params.id); // if this rejects, Express catches it
if (!user) throw new HttpError(404, 'User not found');
res.json(user);
});
A small error class
export class HttpError extends Error {
constructor(status, message, details) {
super(message);
this.status = status;
this.details = details;
}
}
One error middleware at the end
// after all routes
app.use((req, res) => res.status(404).json({ error: 'Not found' }));
app.use((err, req, res, next) => {
const status = err.status ?? 500;
if (status >= 500) console.error(err); // log the details server-side
res.status(status).json({
error: status >= 500 ? 'Something went wrong' : err.message, // don't leak internals
...(err.details && { details: err.details }),
});
});
Error middleware is recognised by having exactly four parameters, so keep next even if you don't use it.
Other Express 5 changes to know
- Route path syntax changed: wildcards must be named, e.g.
'/files/*path', and optional segments use braces:'/docs{/:section}'. req.queryis a getter and no longer writable.res.status()only accepts valid HTTP status codes.- Some deprecated methods were removed (for example
res.sendfile; useres.sendFile).
Don't forget the process level
process.on('unhandledRejection', (reason) => {
console.error('Unhandled rejection', reason);
process.exitCode = 1;
});
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.