Standardizing Express.js Error Handling with One Library

If you’ve been working with Express.js for a while, you know the struggle. You start a project, and soon your controllers look like this:

// The "Bad" Way
app.post('/users', async (req, res) => {
  try {
    // ... logic
  } catch (error) {
    console.error(error);
    if (error.code === 'P2002') { // Prisma unique constraint
        return res.status(400).json({ message: 'User already exists' });
    }
    // ... 10 more if/else checks
    res.status(500).json({ message: 'Something went wrong' });
  }
});

It’s repetitive, hard to maintain, and prone to bugs. I got tired of copy-pasting error handling logic between my projects, so I built a tool to fix it once and for all.

​Meet ds-express-errors.

What is it?

ds-express-errors is a centralized, type-safe error handling library for Node.js & Express. It aims to replace all your manual try-catch blocks and status code management with a clean, declarative API.
​Here is why I think it’s worth checking out:

Ready-to-use Presets 🛠️

​Forget about remembering if “Forbidden” is 401 or 403. Just use the presets.

import { Errors } from 'ds-express-errors';

if (!user) {
  throw Errors.NotFound('User not found'); // Automatically sends 404
}

if (!user.hasAccess) {
  throw Errors.Forbidden('Access denied'); // Automatically sends 403
}

Auto-Mapping (The Magic 🪄)

​This is my favorite part. If you use Zod, Prisma, or Mongoose, the library automatically detects their native errors and converts them into readable HTTP 400 Bad Requests.

Example with Zod:
You don’t need to manually parse error.issues.

Input (Invalid):

{ "email": "invalid-email" }

Output (Automatic):

{
  "status": "fail",
  "method": "GET",
  "url": "/login",
  "message": "Validation error: email: Invalid email",
  "stack": // showed when NODE_ENV=development
}

No More try/catch


With the included asyncHandler, your controllers become clean again.

import { asyncHandler, Errors } from 'ds-express-errors';

const createUser = asyncHandler(async (req, res) => {
  const user = await db.create(req.body); // If this throws, it's handled automatically!
  res.json(user);
});

Graceful Shutdown 🛑

​It also handles process-level errors (uncaughtException, unhandledRejection) and allows you to close database connections gracefully before crashing.

import { initGlobalHandlers } from 'ds-express-errors';

initGlobalHandlers({
  onCrash: () => {
    db.disconnect();
    server.close();
  }
});

📦 How to use it?

​Installation is standard:

npm install ds-express-errors

📚 Documentation


I’ve built a full documentation website where you can see advanced usage, API references, and more examples:

👉ds-express-errors.dev

Conclusion

​Building this library helped me standardize my backend projects, and I hope it helps you too. It’s fully typed (TypeScript), lightweight, and production-ready.

Give it a try and let me know what you think! Any feedback or stars on a GitHub are highly appreciated. ❤️

Similar Posts