← Back to Blog
Jul 4, 20265 min read

Express.js Middleware Architecture: Common Error Handling Pitfalls

ExpressNode.jsError HandlingMiddleware
Express.js Middleware Architecture: Common Error Handling Pitfalls

Express.js is the backbone of millions of Node.js servers. Its simple middleware chain architecture makes it highly modular. However, it is surprisingly easy to make fatal mistakes in how you handle async errors inside middleware functions.

Pitfall 1: Leaking Stack Traces to the Client

When an error occurs, displaying raw database exceptions or stack traces to visitors is a major security risk. It exposes details of your schema and server directory structures to potential hackers.

To avoid this, always register a Global Error Handler at the very end of your Express router configuration:

app.use((err, req, res, next) => {
  console.error(err.stack); // Log internally
  res.status(500).json({ 
    error: "Something went wrong! Please try again later." 
  });
});

Pitfall 2: Silent Async Failures (The Server Freeze)

In older Express versions, throwing an error inside an async middleware function without catching it would lead to an unhandled promise rejection, which could hang the request forever or even crash the Node runtime. Even in modern runtimes, it causes memory leaks.

Always wrap asynchronous tasks in try-catch blocks and pass the error to the next middleware callback:

app.get("/api/data", async (req, res, next) => {
  try {
    const data = await fetchExternalData();
    res.json(data);
  } catch (err) {
    next(err); // Hands over control to your global error middleware
  }
});

By enforcing global error boundaries and wrapping all async actions cleanly, you build resilient services that keep running smoothly even under unexpected network failures.

Nazmul Hasan

Written by

Nazmul Hasan

Software Engineer & Entrepreneur