ExpressJS - Error handling
Express.js - Modern Error Handling
Section titled “Express.js - Modern Error Handling”Robust error handling is a critical part of any production application. It prevents the server from crashing, helps in debugging, and provides meaningful feedback to users without exposing sensitive implementation details.
The Error-Handling Middleware
Section titled “The Error-Handling Middleware”In Express, error handling is done using a special type of middleware. This middleware function has four arguments instead of the usual three: (err, req, res, next). This signature is how Express identifies it as an error-handling middleware.
This middleware should be defined last, after all other app.use() and route calls.
app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('Something broke!');});Triggering the Error Handler
Section titled “Triggering the Error Handler”You can trigger the error-handling middleware in two ways:
- Synchronous Errors: If an error is thrown in synchronous code within a route handler or middleware, Express will catch it and pass it to the error handler automatically.
- Asynchronous Errors: For errors in asynchronous code (like database queries or API calls), you must catch them and pass them to
next().
Example: Passing an Error with next()
Section titled “Example: Passing an Error with next()”In this example, we manually create an error and pass it to next(err). This skips all subsequent non-error-handling middleware and routes and goes directly to our error handler.
import express from 'express';
const app = express();
app.get('/problem', (req, res, next) => { // Simulate an error const err = new Error('This is a simulated error.'); err.status = 418; // You can add custom properties
// Pass the error to the next middleware next(err);});
// Define other routes and middleware here...app.get('/', (req, res) => res.send('Welcome!'));
// The centralized error handler (must be last)app.use((err, req, res, next) => { console.error('Error occurred:', err.message);
// Set a default status code if none is provided const statusCode = err.status || 500;
res.status(statusCode).json({ error: { message: err.message || 'An internal server error occurred.' } });});
app.listen(3000, () => console.log('Server running on port 3000'));Output
Section titled “Output”When you visit http://localhost:3000/problem, the browser will display a JSON response with a 418 status code:
{ "error": { "message": "This is a simulated error." }}Handling Asynchronous Errors
Section titled “Handling Asynchronous Errors”Handling errors in async/await functions requires a try...catch block to pass the error to next().
import { findUserById } from './db'; // Assume this is an async DB function
app.get('/users/:id', async (req, res, next) => { try { const user = await findUserById(req.params.id); if (!user) { // Create a specific error for 'not found' const err = new Error('User not found'); err.status = 404; return next(err); } res.json(user); } catch (error) { // Catch database errors or other exceptions next(error); }});Modern Development Tip: Libraries like express-async-errors can automatically handle this for you. By simply importing the library, you can eliminate the need for try...catch blocks in your async route handlers.
Best Practices for Error Handling
Section titled “Best Practices for Error Handling”- Centralize Error Handling: Use a single, centralized error-handling middleware for consistent error responses.
- Don’t Leak Implementation Details: In a production environment, never send the full error stack trace to the client. Log it for debugging but send a generic, user-friendly message.
- Create Custom Error Classes: For more structured error handling, extend the built-in
Errorclass to create custom error types (e.g.,ApiError,NotFoundError) that can hold a status code and other metadata. - Handle Uncaught Exceptions: For ultimate stability, listen for
process.on('uncaughtException')andprocess.on('unhandledRejection')to catch errors outside the Express request-response cycle. Log the error and gracefully shut down the server.