Skip to Content
πŸŽ‰ Welcome to my notes πŸŽ‰
Express.jsError Handling in Express πŸ›‘οΈ

Error Handling in Express πŸ›‘οΈ

When an error occurs during the request-response cycle, you need a way to catch it and send a clean, helpful response to the client. Express has a default error handler, but for any real application, you’ll want to create your own centralized error-handling logic.

The Default Error Handler

If an error is thrown in your application and you don’t handle it yourself, Express’s built-in error handler will catch it. By default, it sends the error’s stack trace to the client in an HTML page. This is useful for development but is not suitable for production because it can leak sensitive information about your server’s structure.

Creating a Custom Error-Handling Middleware

The standard pattern in Express is to create a special β€œerror-handling” middleware. This is a centralized place to process any errors that occur in your route handlers or other middleware.

An error-handling middleware is unique because it has a different signature with four arguments instead of three:

(err, req, res, next)

  1. err: The error object. This could be an error you created, or one thrown by a library.
  2. req, res, next: The same objects as in regular middleware.

Crucial Rule: The error-handling middleware must be defined at the very end of your middleware and route stack, after all other app.use() calls and route definitions.

How to Trigger the Error Handler

From a route handler or regular middleware, you trigger the error handler by calling next() with an argument.

next(someErrorObject)

When you call next() with an error, Express skips all subsequent regular middleware and route handlers and jumps directly to the first error-handling middleware it finds.

πŸ’» Code Example: A Centralized Error Handler

This example demonstrates a complete setup with a 404 handler and a centralized error handler.

app.js
const express = require("express"); const app = express(); // A successful route app.get("/", (req, res) => { res.send("Welcome!"); }); // A route that throws a synchronous error app.get("/error-sync", (req, res) => { throw new Error("This is a synchronous error!"); }); // A route with an asynchronous error app.get("/error-async", (req, res, next) => { setTimeout(() => { // For async errors, you MUST pass the error to next(). next(new Error("This is an asynchronous error!")); }, 1000); }); // --- CATCH-ALL FOR 404 ERRORS --- // This middleware runs if no route above has matched. app.use((req, res, next) => { res.status(404).json({ error: "Not Found" }); }); // --- CENTRALIZED ERROR HANDLER --- // This middleware has 4 arguments, which Express recognizes as an error handler. // It must be defined LAST. app.use((err, req, res, next) => { console.error(err.stack); // Log the error for debugging // Send a generic, user-friendly error response res.status(500).json({ error: "Something went wrong on the server.", }); }); app.listen(3000, () => console.log("Server is running on port 3000"));

Synchronous vs. Asynchronous Errors

How Express handles errors depends on whether they occur in synchronous or asynchronous code.

  • Synchronous Code: If you throw new Error() inside a synchronous route handler, Express will automatically catch it and pass it to your error-handling middleware.
  • Asynchronous Code (Callbacks/Promises): For errors that occur inside asynchronous code (like a database callback or a .then() block), you must catch them and pass them to next() manually (e.g., next(err)).
  • async/await in Express 5: A major improvement in modern Express (v5) is that errors thrown inside an async route handler are now automatically caught and passed to next(), just like synchronous errors. This greatly simplifies async error handling.

✨ Summary

  • A custom error-handling middleware is the standard pattern for centralized error logic in Express.
  • It is a special middleware with four arguments: (err, req, res, next).
  • It must be defined last, after all other app.use() and route calls.
  • You trigger the error handler by calling next(err) with an error object from a route or other middleware.
  • Remember the distinction between how synchronous and asynchronous errors are handled, and leverage the automatic handling for async/await in modern Express.
Last updated on