Mastering Error Handling in Node.js & Express: A Step-by-Step Guide
Effective Error Handling in Node.js & Express.js
Error handling is a critical part of any robust Express.js application. In this article, we’ll walk through handling errors in an Express-based Node.js project, from basic try-catch blocks to custom error handlers and middleware.
How Express Handles Errors by Default
When an error is thrown in an Express route, the default error handler attempts to catch and log it. However, in Express 4, unhandled errors in asynchronous route handlers can crash the server. To prevent this, developers must use try-catch blocks and explicitly pass errors to the next
function.
Handling Errors with Try-Catch (Express 4)
To prevent server crashes, you should wrap asynchronous route handlers in try-catch blocks:
app.get('/task/:id', async (req, res, next) => {
try {
const task = await getTaskById(req.params.id);
res.json(task);
} catch (error) {
next(error);
}
});
This ensures that errors are forwarded to the Express error handler instead of breaking the app.
Express 5: No More Try-Catch!
With Express 5, unhandled promise rejections are automatically caught, eliminating the need for manual try-catch in every route. To upgrade to Express 5:
npm install express@next
Once upgraded, Express will handle async errors by default.
Creating a Custom Error Handler
A custom error handler allows better control over error responses. We define it in error-handler.ts
:
export default function errorHandler(err, req, res, next) {
if (res.headersSent) return next(err);
res.status(500).json({ message: err.message || 'Internal Server Error' });
}
Adding this as middleware in server.ts
ensures all errors are handled consistently:
app.use(errorHandler);
🚀Boost your career with 👉 IBM Full Stack Software Developer Certificate
Using Custom Errors for Better Error Management
Instead of generic errors, we can define structured errors:
class CustomError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
}
}
A specialized error for missing entities might look like this:
class EntityNotFoundError extends CustomError {
constructor() {
super('Entity not found', 404);
}
}
This makes it easier to return precise error messages to users.
Final Thoughts
By implementing custom error handling and structured errors, Express applications become more stable and user-friendly. Upgrading to Express 5 further simplifies error management by eliminating unnecessary try-catch blocks.