Lesson 32 +10 XP

Async Error Wrapping (express-async-handler)

Handling Unhandled Rejections in Async Routes

Synchronous errors inside route handlers are automatically caught by Express. However, unhandled promise rejections inside async route functions will hang the request unless explicitly caught or wrapped!

Manual try/catch Approach

app.get("/users/:id", async (req, res, next) => {
  try {
    const user = await User.findById(req.params.id);
    if (!user) throw new Error("User not found");
    res.json(user);
  } catch (err) {
    next(err); // Must call next(err) manually!
  }
});

Cleaner Solution: Higher-Order Async Wrapper

Avoid repeating try/catch in dozens of routes by wrapping async route handlers:

// Higher-order function wrapper
const asyncHandler = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

// Usage with asyncHandler (No try/catch block needed!)
app.get("/users/:id", asyncHandler(async (req, res) => {
  const user = await User.findById(req.params.id);
  if (!user) {
    const error = new Error("User not found");
    error.statusCode = 404;
    throw error;
  }
  res.json(user);
}));

TL;DR

  • Async routes throw unhandled rejections if errors are not caught.
  • Use an asyncHandler utility or the express-async-errors package to eliminate repetitive try/catch blocks.