Standardizing Express.js Error Handling with One Library
Source: Dev.to

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 replaces manual try‑catch blocks and status‑code management with a clean, declarative API.
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 🪄)
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
Input (Invalid)
{ "email": "invalid-email" }
Output (Automatic)
{
"status": "fail",
"method": "GET",
"url": "/login",
"message": "Validation error: email: Invalid email",
"stack": "..." // shown 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
A full documentation site is available with advanced usage, API references, and more examples:
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 repository are highly appreciated. ❤️