100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js

Error Handling in Express

Master synchronous and asynchronous error handling in Express using 4-argument error middleware.

Building APIsIntermediate11 min readJul 8, 2026
Analogies

Introduction

Robust APIs must handle errors gracefully instead of crashing or leaking stack traces to clients. Express provides a built-in mechanism for centralized error handling through special middleware functions that accept four arguments. Synchronous errors are caught automatically, but asynchronous errors — such as rejected promises inside async route handlers — need to be explicitly forwarded to Express.

🏏

Cricket analogy: A well-run team doesn't collapse into chaos after a bad umpiring decision — there's a designated process (centralized error middleware) for lodging a formal complaint; a clear no-ball is caught by the on-field umpire automatically, but a disputed boundary needs someone to actively call for a review (forwarding async errors) or the match just continues on a wrong call.

Syntax

javascript
// Error-handling middleware has exactly 4 parameters
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(err.status || 500).json({ error: err.message || 'Server error' });
});

Explanation

Express identifies error-handling middleware by its signature: it must accept exactly four arguments (err, req, res, next), and must be registered after all other app.use() and route calls. For synchronous code, throwing an error inside a route handler is automatically caught by Express and routed to this middleware. For asynchronous code (promises, async/await), errors are NOT caught automatically — you must call next(err) inside a .catch() block, or wrap async handlers in a helper that catches rejected promises and forwards them via next().

🏏

Cricket analogy: The complaints committee is identifiable by its exact structure — it only convenes after all match officials have filed their reports, never before; a blatant no-ball is flagged automatically by the on-field umpire, but a slow-motion review of a close catch needs someone to explicitly submit it to the committee (.catch(next)) or it never gets reviewed.

Example

javascript
// Helper to catch async errors automatically
function asyncHandler(fn) {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
}

app.get('/users/:id', asyncHandler(async (req, res) => {
  const user = await db.findUserById(req.params.id);
  if (!user) {
    const err = new Error('User not found');
    err.status = 404;
    throw err;
  }
  res.json(user);
}));

// Centralized error-handling middleware, registered last
app.use((err, req, res, next) => {
  res.status(err.status || 500).json({ error: err.message });
});

Output

If db.findUserById rejects or the user is not found, asyncHandler catches the thrown error and passes it to next(), which invokes the error-handling middleware, producing a JSON response like { "error": "User not found" } with status 404 instead of an unhandled promise rejection or a hung request.

🏏

Cricket analogy: If a player's registration lookup fails or the player simply isn't registered, the system catches the rejected lookup and forwards it to the complaints desk, which returns a clear 'Player not found' ruling instead of leaving the match official waiting indefinitely for an answer that never comes.

Key Takeaways

Errors thrown inside async functions are NOT automatically caught by Express (in Express 4). You must call next(err) explicitly or use a wrapper like asyncHandler; otherwise the request will hang or crash the process with an unhandled rejection.

  • Error-handling middleware is identified by having exactly 4 parameters: (err, req, res, next).
  • Error-handling middleware must be registered after all routes and other middleware.
  • Synchronous throws inside route handlers are caught automatically by Express 4.
  • Async errors must be forwarded manually via next(err) or a wrapper function like asyncHandler.
  • Centralizing error handling keeps response formatting and logging consistent across the app.

Practice what you learned

Was this page helpful?

Topics covered

#NodeJs#NodeJsExpressStudyNotes#WebDevelopment#ErrorHandlingInExpress#Error#Handling#Express#Syntax#ErrorHandling#StudyNotes#SkillVeris