DEV Community

Jeremiah Deku
Jeremiah Deku

Posted on

The exact error handling pattern I use in every Express.js + TypeScript REST API

Most Node.js error handling tutorials show you try/catch.
That's not enough for production.
I learned this the hard way. A silent catch block swallowed a database failure. My API returned 200. The user's data never saved. Nobody knew for 48 hours.
After that incident, I built a pattern I now wire into every Express + TypeScript REST API I ship. It has four parts. Every part earns its place.

Here's exactly what it looks like โ€” and why each piece matters.


๐—ง๐—ต๐—ฒ ๐—ฝ๐—ฟ๐—ผ๐—ฏ๐—น๐—ฒ๐—บ ๐˜„๐—ถ๐˜๐—ต ๐—ฑ๐—ฒ๐—ณ๐—ฎ๐˜‚๐—น๐˜ ๐—˜๐˜…๐—ฝ๐—ฟ๐—ฒ๐˜€๐˜€ ๐—ฒ๐—ฟ๐—ฟ๐—ผ๐—ฟ ๐—ต๐—ฎ๐—ป๐—ฑ๐—น๐—ถ๐—ป๐—ด
Out of the box, Express does this when something throws:

๐˜ข๐˜ฑ๐˜ฑ.๐˜จ๐˜ฆ๐˜ต('/๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜ด/:๐˜ช๐˜ฅ', ๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค (๐˜ณ๐˜ฆ๐˜ฒ, ๐˜ณ๐˜ฆ๐˜ด) => {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ถ๐˜ด๐˜ฆ๐˜ณ = ๐˜ข๐˜ธ๐˜ข๐˜ช๐˜ต ๐˜ฅ๐˜ฃ.๐˜ง๐˜ช๐˜ฏ๐˜ฅ๐˜‰๐˜บ๐˜๐˜ฅ(๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฑ๐˜ข๐˜ณ๐˜ข๐˜ฎ๐˜ด.๐˜ช๐˜ฅ); // ๐˜ต๐˜ฉ๐˜ณ๐˜ฐ๐˜ธ๐˜ด? ๐˜ค๐˜ณ๐˜ข๐˜ด๐˜ฉ๐˜ฆ๐˜ด ๐˜ต๐˜ฉ๐˜ฆ ๐˜ฑ๐˜ณ๐˜ฐ๐˜ค๐˜ฆ๐˜ด๐˜ด
๐˜ณ๐˜ฆ๐˜ด.๐˜ซ๐˜ด๐˜ฐ๐˜ฏ(๐˜ถ๐˜ด๐˜ฆ๐˜ณ);
});

If db.findById throws, Express doesn't catch it in async route handlers by default. Your server either crashes or hangs. The client waits forever.
Even if you add try/catch:
๐˜ข๐˜ฑ๐˜ฑ.๐˜จ๐˜ฆ๐˜ต('/๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜ด/:๐˜ช๐˜ฅ', ๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค (๐˜ณ๐˜ฆ๐˜ฒ, ๐˜ณ๐˜ฆ๐˜ด) => {
๐˜ต๐˜ณ๐˜บ {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ถ๐˜ด๐˜ฆ๐˜ณ = ๐˜ข๐˜ธ๐˜ข๐˜ช๐˜ต ๐˜ฅ๐˜ฃ.๐˜ง๐˜ช๐˜ฏ๐˜ฅ๐˜‰๐˜บ๐˜๐˜ฅ(๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฑ๐˜ข๐˜ณ๐˜ข๐˜ฎ๐˜ด.๐˜ช๐˜ฅ);
๐˜ณ๐˜ฆ๐˜ด.๐˜ซ๐˜ด๐˜ฐ๐˜ฏ(๐˜ถ๐˜ด๐˜ฆ๐˜ณ);
} ๐˜ค๐˜ข๐˜ต๐˜ค๐˜ฉ (๐˜ฆ๐˜ณ๐˜ณ) {
๐˜ณ๐˜ฆ๐˜ด.๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด(500).๐˜ซ๐˜ด๐˜ฐ๐˜ฏ({ ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ }); // ๐˜ญ๐˜ฆ๐˜ข๐˜ฌ๐˜ด ๐˜ช๐˜ฏ๐˜ต๐˜ฆ๐˜ณ๐˜ฏ๐˜ข๐˜ญ๐˜ด
}
});

Now you're leaking internal error messages to clients, losing stack traces in logs, and duplicating error logic across every route.
Here's what I do instead.


๐—ฃ๐—ฎ๐—ฟ๐˜ ๐Ÿญ: ๐—” ๐˜๐˜†๐—ฝ๐—ฒ๐—ฑ ๐—”๐—ฝ๐—ฝ๐—˜๐—ฟ๐—ฟ๐—ผ๐—ฟ ๐—ฐ๐—น๐—ฎ๐˜€๐˜€
Every error in the system extends a single base class. No raw new Error() anywhere in the codebase.
// ๐˜ด๐˜ณ๐˜ค/๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜ด/๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ.๐˜ต๐˜ด

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ค๐˜ญ๐˜ข๐˜ด๐˜ด ๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ ๐˜ฆ๐˜น๐˜ต๐˜ฆ๐˜ฏ๐˜ฅ๐˜ด ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ค๐˜ต๐˜ฐ๐˜ณ(
๐˜ฑ๐˜ถ๐˜ฃ๐˜ญ๐˜ช๐˜ค ๐˜ณ๐˜ฆ๐˜ข๐˜ฅ๐˜ฐ๐˜ฏ๐˜ญ๐˜บ ๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ: ๐˜ด๐˜ต๐˜ณ๐˜ช๐˜ฏ๐˜จ,
๐˜ฑ๐˜ถ๐˜ฃ๐˜ญ๐˜ช๐˜ค ๐˜ณ๐˜ฆ๐˜ข๐˜ฅ๐˜ฐ๐˜ฏ๐˜ญ๐˜บ ๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด๐˜Š๐˜ฐ๐˜ฅ๐˜ฆ: ๐˜ฏ๐˜ถ๐˜ฎ๐˜ฃ๐˜ฆ๐˜ณ,
๐˜ฑ๐˜ถ๐˜ฃ๐˜ญ๐˜ช๐˜ค ๐˜ณ๐˜ฆ๐˜ข๐˜ฅ๐˜ฐ๐˜ฏ๐˜ญ๐˜บ ๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ: ๐˜ด๐˜ต๐˜ณ๐˜ช๐˜ฏ๐˜จ,
๐˜ฑ๐˜ถ๐˜ฃ๐˜ญ๐˜ช๐˜ค ๐˜ณ๐˜ฆ๐˜ข๐˜ฅ๐˜ฐ๐˜ฏ๐˜ญ๐˜บ ๐˜ช๐˜ด๐˜–๐˜ฑ๐˜ฆ๐˜ณ๐˜ข๐˜ต๐˜ช๐˜ฐ๐˜ฏ๐˜ข๐˜ญ: ๐˜ฃ๐˜ฐ๐˜ฐ๐˜ญ๐˜ฆ๐˜ข๐˜ฏ = ๐˜ต๐˜ณ๐˜ถ๐˜ฆ
) {
๐˜ด๐˜ถ๐˜ฑ๐˜ฆ๐˜ณ(๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ);
๐˜ต๐˜ฉ๐˜ช๐˜ด.๐˜ฏ๐˜ข๐˜ฎ๐˜ฆ = ๐˜ต๐˜ฉ๐˜ช๐˜ด.๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ค๐˜ต๐˜ฐ๐˜ณ.๐˜ฏ๐˜ข๐˜ฎ๐˜ฆ;
๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ.๐˜ค๐˜ข๐˜ฑ๐˜ต๐˜ถ๐˜ณ๐˜ฆ๐˜š๐˜ต๐˜ข๐˜ค๐˜ฌ๐˜›๐˜ณ๐˜ข๐˜ค๐˜ฆ(๐˜ต๐˜ฉ๐˜ช๐˜ด, ๐˜ต๐˜ฉ๐˜ช๐˜ด.๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ค๐˜ต๐˜ฐ๐˜ณ);
}
}

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ค๐˜ญ๐˜ข๐˜ด๐˜ด ๐˜•๐˜ฐ๐˜ต๐˜๐˜ฐ๐˜ถ๐˜ฏ๐˜ฅ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ ๐˜ฆ๐˜น๐˜ต๐˜ฆ๐˜ฏ๐˜ฅ๐˜ด ๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ค๐˜ต๐˜ฐ๐˜ณ(๐˜ณ๐˜ฆ๐˜ด๐˜ฐ๐˜ถ๐˜ณ๐˜ค๐˜ฆ: ๐˜ด๐˜ต๐˜ณ๐˜ช๐˜ฏ๐˜จ) {
๐˜ด๐˜ถ๐˜ฑ๐˜ฆ๐˜ณ(${๐˜ณ๐˜ฆ๐˜ด๐˜ฐ๐˜ถ๐˜ณ๐˜ค๐˜ฆ} ๐˜ฏ๐˜ฐ๐˜ต ๐˜ง๐˜ฐ๐˜ถ๐˜ฏ๐˜ฅ, 404, '๐˜•๐˜–๐˜›_๐˜๐˜–๐˜œ๐˜•๐˜‹');
}
}

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ค๐˜ญ๐˜ข๐˜ด๐˜ด ๐˜๐˜ข๐˜ญ๐˜ช๐˜ฅ๐˜ข๐˜ต๐˜ช๐˜ฐ๐˜ฏ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ ๐˜ฆ๐˜น๐˜ต๐˜ฆ๐˜ฏ๐˜ฅ๐˜ด ๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ค๐˜ต๐˜ฐ๐˜ณ(๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ: ๐˜ด๐˜ต๐˜ณ๐˜ช๐˜ฏ๐˜จ) {
๐˜ด๐˜ถ๐˜ฑ๐˜ฆ๐˜ณ(๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ, 422, '๐˜๐˜ˆ๐˜“๐˜๐˜‹๐˜ˆ๐˜›๐˜๐˜–๐˜•_๐˜Œ๐˜™๐˜™๐˜–๐˜™');
}
}

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ค๐˜ญ๐˜ข๐˜ด๐˜ด ๐˜œ๐˜ฏ๐˜ข๐˜ถ๐˜ต๐˜ฉ๐˜ฐ๐˜ณ๐˜ช๐˜ป๐˜ฆ๐˜ฅ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ ๐˜ฆ๐˜น๐˜ต๐˜ฆ๐˜ฏ๐˜ฅ๐˜ด ๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต๐˜ณ๐˜ถ๐˜ค๐˜ต๐˜ฐ๐˜ณ() {
๐˜ด๐˜ถ๐˜ฑ๐˜ฆ๐˜ณ('๐˜œ๐˜ฏ๐˜ข๐˜ถ๐˜ต๐˜ฉ๐˜ฐ๐˜ณ๐˜ช๐˜ป๐˜ฆ๐˜ฅ', 401, '๐˜œ๐˜•๐˜ˆ๐˜œ๐˜›๐˜๐˜–๐˜™๐˜๐˜ก๐˜Œ๐˜‹');
}
}

isOperational is the key flag. true means this is an expected failure โ€” a user not found, a bad payload. false means something unexpected broke โ€” a DB connection dropped, a third-party SDK crashed. Your error handler treats these differently.


๐—ฃ๐—ฎ๐—ฟ๐˜ ๐Ÿฎ: ๐—” ๐—ฐ๐—ฒ๐—ป๐˜๐—ฟ๐—ฎ๐—น ๐—ฒ๐—ฟ๐—ฟ๐—ผ๐—ฟ ๐—ต๐—ฎ๐—ป๐—ฑ๐—น๐—ฒ๐—ฟ ๐—บ๐—ถ๐—ฑ๐—ฑ๐—น๐—ฒ๐˜„๐—ฎ๐—ฟ๐—ฒ

// ๐˜ด๐˜ณ๐˜ค/๐˜ฎ๐˜ช๐˜ฅ๐˜ฅ๐˜ญ๐˜ฆ๐˜ธ๐˜ข๐˜ณ๐˜ฆ/๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ.๐˜ต๐˜ด
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต, ๐˜™๐˜ฆ๐˜ด๐˜ฑ๐˜ฐ๐˜ฏ๐˜ด๐˜ฆ, ๐˜•๐˜ฆ๐˜น๐˜ต๐˜๐˜ถ๐˜ฏ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '../๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜ด/๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜ญ๐˜ฐ๐˜จ๐˜จ๐˜ฆ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '../๐˜ญ๐˜ช๐˜ฃ/๐˜ญ๐˜ฐ๐˜จ๐˜จ๐˜ฆ๐˜ณ';

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ง๐˜ถ๐˜ฏ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ(
๐˜ฆ๐˜ณ๐˜ณ: ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ,
๐˜ณ๐˜ฆ๐˜ฒ: ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต,
๐˜ณ๐˜ฆ๐˜ด: ๐˜™๐˜ฆ๐˜ด๐˜ฑ๐˜ฐ๐˜ฏ๐˜ด๐˜ฆ,
๐˜ฏ๐˜ฆ๐˜น๐˜ต: ๐˜•๐˜ฆ๐˜น๐˜ต๐˜๐˜ถ๐˜ฏ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ
): ๐˜ท๐˜ฐ๐˜ช๐˜ฅ {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ฅ = ๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฉ๐˜ฆ๐˜ข๐˜ฅ๐˜ฆ๐˜ณ๐˜ด['๐˜น-๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต-๐˜ช๐˜ฅ'] ๐˜ข๐˜ด ๐˜ด๐˜ต๐˜ณ๐˜ช๐˜ฏ๐˜จ;

๐˜ช๐˜ง (๐˜ฆ๐˜ณ๐˜ณ ๐˜ช๐˜ฏ๐˜ด๐˜ต๐˜ข๐˜ฏ๐˜ค๐˜ฆ๐˜ฐ๐˜ง ๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ && ๐˜ฆ๐˜ณ๐˜ณ.๐˜ช๐˜ด๐˜–๐˜ฑ๐˜ฆ๐˜ณ๐˜ข๐˜ต๐˜ช๐˜ฐ๐˜ฏ๐˜ข๐˜ญ) {
// ๐˜Œ๐˜น๐˜ฑ๐˜ฆ๐˜ค๐˜ต๐˜ฆ๐˜ฅ ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ โ€” ๐˜ญ๐˜ฐ๐˜จ ๐˜ญ๐˜ช๐˜จ๐˜ฉ๐˜ต๐˜ญ๐˜บ, ๐˜ณ๐˜ฆ๐˜ด๐˜ฑ๐˜ฐ๐˜ฏ๐˜ฅ ๐˜ค๐˜ญ๐˜ฆ๐˜ข๐˜ฏ๐˜ญ๐˜บ
๐˜ญ๐˜ฐ๐˜จ๐˜จ๐˜ฆ๐˜ณ.๐˜ธ๐˜ข๐˜ณ๐˜ฏ({
๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ฅ,
๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ,
๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ,
๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด๐˜Š๐˜ฐ๐˜ฅ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด๐˜Š๐˜ฐ๐˜ฅ๐˜ฆ,
});

๐˜ณ๐˜ฆ๐˜ด.๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด(๐˜ฆ๐˜ณ๐˜ณ.๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด๐˜Š๐˜ฐ๐˜ฅ๐˜ฆ).๐˜ซ๐˜ด๐˜ฐ๐˜ฏ({
  ๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด: '๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ',
  ๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ,
  ๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ,
});
๐˜ณ๐˜ฆ๐˜ต๐˜ถ๐˜ณ๐˜ฏ;
Enter fullscreen mode Exit fullscreen mode

}

// ๐˜œ๐˜ฏ๐˜ฆ๐˜น๐˜ฑ๐˜ฆ๐˜ค๐˜ต๐˜ฆ๐˜ฅ ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ โ€” ๐˜ญ๐˜ฐ๐˜จ ๐˜ฆ๐˜ท๐˜ฆ๐˜ณ๐˜บ๐˜ต๐˜ฉ๐˜ช๐˜ฏ๐˜จ, ๐˜ณ๐˜ฆ๐˜ด๐˜ฑ๐˜ฐ๐˜ฏ๐˜ฅ ๐˜จ๐˜ฆ๐˜ฏ๐˜ฆ๐˜ณ๐˜ช๐˜ค๐˜ข๐˜ญ๐˜ญ๐˜บ
๐˜ญ๐˜ฐ๐˜จ๐˜จ๐˜ฆ๐˜ณ.๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ({
๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ฅ,
๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ,
๐˜ด๐˜ต๐˜ข๐˜ค๐˜ฌ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ด๐˜ต๐˜ข๐˜ค๐˜ฌ,
๐˜ฏ๐˜ข๐˜ฎ๐˜ฆ: ๐˜ฆ๐˜ณ๐˜ณ.๐˜ฏ๐˜ข๐˜ฎ๐˜ฆ,
});

๐˜ณ๐˜ฆ๐˜ด.๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด(500).๐˜ซ๐˜ด๐˜ฐ๐˜ฏ({
๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด: '๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ',
๐˜ค๐˜ฐ๐˜ฅ๐˜ฆ: '๐˜๐˜•๐˜›๐˜Œ๐˜™๐˜•๐˜ˆ๐˜“_๐˜Œ๐˜™๐˜™๐˜–๐˜™',
๐˜ฎ๐˜ฆ๐˜ด๐˜ด๐˜ข๐˜จ๐˜ฆ: '๐˜š๐˜ฐ๐˜ฎ๐˜ฆ๐˜ต๐˜ฉ๐˜ช๐˜ฏ๐˜จ ๐˜ธ๐˜ฆ๐˜ฏ๐˜ต ๐˜ธ๐˜ณ๐˜ฐ๐˜ฏ๐˜จ. ๐˜—๐˜ญ๐˜ฆ๐˜ข๐˜ด๐˜ฆ ๐˜ต๐˜ณ๐˜บ ๐˜ข๐˜จ๐˜ข๐˜ช๐˜ฏ.',
});
}

Clients never see stack traces, internal messages, or database query strings. Logs capture everything you need to debug. The requestId ties the log line back to the exact request that failed.


๐—ฃ๐—ฎ๐—ฟ๐˜ ๐Ÿฏ: ๐—”๐—ป ๐—ฎ๐˜€๐˜†๐—ป๐—ฐ ๐˜„๐—ฟ๐—ฎ๐—ฝ๐—ฝ๐—ฒ๐—ฟ ๐˜๐—ผ ๐—ฐ๐—ฎ๐˜๐—ฐ๐—ต ๐—ฟ๐—ผ๐˜‚๐˜๐—ฒ ๐—ฒ๐—ฟ๐—ฟ๐—ผ๐—ฟ๐˜€
Express doesn't catch errors thrown inside async route handlers unless you explicitly call next(err). Writing try/catch in every route is noisy and forgettable.
This wrapper handles it once:

// ๐˜ด๐˜ณ๐˜ค/๐˜ถ๐˜ต๐˜ช๐˜ญ๐˜ด/๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ.๐˜ต๐˜ด
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต, ๐˜™๐˜ฆ๐˜ด๐˜ฑ๐˜ฐ๐˜ฏ๐˜ด๐˜ฆ, ๐˜•๐˜ฆ๐˜น๐˜ต๐˜๐˜ถ๐˜ฏ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ, ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด';

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ง๐˜ถ๐˜ฏ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ ๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ(๐˜ง๐˜ฏ: ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ): ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ {
๐˜ณ๐˜ฆ๐˜ต๐˜ถ๐˜ณ๐˜ฏ (๐˜ณ๐˜ฆ๐˜ฒ: ๐˜™๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต, ๐˜ณ๐˜ฆ๐˜ด: ๐˜™๐˜ฆ๐˜ด๐˜ฑ๐˜ฐ๐˜ฏ๐˜ด๐˜ฆ, ๐˜ฏ๐˜ฆ๐˜น๐˜ต: ๐˜•๐˜ฆ๐˜น๐˜ต๐˜๐˜ถ๐˜ฏ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ) => {
๐˜—๐˜ณ๐˜ฐ๐˜ฎ๐˜ช๐˜ด๐˜ฆ.๐˜ณ๐˜ฆ๐˜ด๐˜ฐ๐˜ญ๐˜ท๐˜ฆ(๐˜ง๐˜ฏ(๐˜ณ๐˜ฆ๐˜ฒ, ๐˜ณ๐˜ฆ๐˜ด, ๐˜ฏ๐˜ฆ๐˜น๐˜ต)).๐˜ค๐˜ข๐˜ต๐˜ค๐˜ฉ(๐˜ฏ๐˜ฆ๐˜น๐˜ต);
};
}

Now routes look like this:

// ๐˜ด๐˜ณ๐˜ค/๐˜ณ๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ด/๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜ด.๐˜ต๐˜ด
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜™๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '../๐˜ถ๐˜ต๐˜ช๐˜ญ๐˜ด/๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜•๐˜ฐ๐˜ต๐˜๐˜ฐ๐˜ถ๐˜ฏ๐˜ฅ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '../๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜ด/๐˜ˆ๐˜ฑ๐˜ฑ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜š๐˜ฆ๐˜ณ๐˜ท๐˜ช๐˜ค๐˜ฆ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '../๐˜ด๐˜ฆ๐˜ณ๐˜ท๐˜ช๐˜ค๐˜ฆ๐˜ด/๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜š๐˜ฆ๐˜ณ๐˜ท๐˜ช๐˜ค๐˜ฆ';

๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ณ๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ณ = ๐˜™๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ณ();

๐˜ณ๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ณ.๐˜จ๐˜ฆ๐˜ต('/:๐˜ช๐˜ฅ', ๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ(๐˜ข๐˜ด๐˜บ๐˜ฏ๐˜ค (๐˜ณ๐˜ฆ๐˜ฒ, ๐˜ณ๐˜ฆ๐˜ด) => {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ถ๐˜ด๐˜ฆ๐˜ณ = ๐˜ข๐˜ธ๐˜ข๐˜ช๐˜ต ๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜š๐˜ฆ๐˜ณ๐˜ท๐˜ช๐˜ค๐˜ฆ.๐˜ง๐˜ช๐˜ฏ๐˜ฅ๐˜‰๐˜บ๐˜๐˜ฅ(๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฑ๐˜ข๐˜ณ๐˜ข๐˜ฎ๐˜ด.๐˜ช๐˜ฅ);

๐˜ช๐˜ง (!๐˜ถ๐˜ด๐˜ฆ๐˜ณ) {
๐˜ต๐˜ฉ๐˜ณ๐˜ฐ๐˜ธ ๐˜ฏ๐˜ฆ๐˜ธ ๐˜•๐˜ฐ๐˜ต๐˜๐˜ฐ๐˜ถ๐˜ฏ๐˜ฅ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ('๐˜œ๐˜ด๐˜ฆ๐˜ณ'); // ๐˜ง๐˜ญ๐˜ฐ๐˜ธ๐˜ด ๐˜ด๐˜ต๐˜ณ๐˜ข๐˜ช๐˜จ๐˜ฉ๐˜ต ๐˜ต๐˜ฐ ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ
}

๐˜ณ๐˜ฆ๐˜ด.๐˜ซ๐˜ด๐˜ฐ๐˜ฏ({ ๐˜ด๐˜ต๐˜ข๐˜ต๐˜ถ๐˜ด: '๐˜ด๐˜ถ๐˜ค๐˜ค๐˜ฆ๐˜ด๐˜ด', ๐˜ฅ๐˜ข๐˜ต๐˜ข: ๐˜ถ๐˜ด๐˜ฆ๐˜ณ });
}));

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ฅ๐˜ฆ๐˜ง๐˜ข๐˜ถ๐˜ญ๐˜ต ๐˜ณ๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ณ;

No try/catch in the route. No next(err) calls manually. Any thrown error โ€” expected or not โ€” flows directly to your central error handler.


๐—ฃ๐—ฎ๐—ฟ๐˜ ๐Ÿฐ: ๐—ช๐—ถ๐—ฟ๐—ถ๐—ป๐—ด ๐—ถ๐˜ ๐—ฎ๐—น๐—น ๐˜๐—ผ๐—ด๐—ฒ๐˜๐—ต๐—ฒ๐—ฟ ๐—ถ๐—ป ๐—˜๐˜…๐—ฝ๐—ฟ๐—ฒ๐˜€๐˜€

// ๐˜ด๐˜ณ๐˜ค/๐˜ข๐˜ฑ๐˜ฑ.๐˜ต๐˜ด
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜ณ๐˜ข๐˜ฏ๐˜ฅ๐˜ฐ๐˜ฎ๐˜œ๐˜œ๐˜๐˜‹ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ '๐˜ค๐˜ณ๐˜บ๐˜ฑ๐˜ต๐˜ฐ';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜™๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ด ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ './๐˜ณ๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ด/๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜ด';
๐˜ช๐˜ฎ๐˜ฑ๐˜ฐ๐˜ณ๐˜ต { ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ } ๐˜ง๐˜ณ๐˜ฐ๐˜ฎ './๐˜ฎ๐˜ช๐˜ฅ๐˜ฅ๐˜ญ๐˜ฆ๐˜ธ๐˜ข๐˜ณ๐˜ฆ/๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ';

๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ข๐˜ฑ๐˜ฑ = ๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด();

๐˜ข๐˜ฑ๐˜ฑ.๐˜ถ๐˜ด๐˜ฆ(๐˜ฆ๐˜น๐˜ฑ๐˜ณ๐˜ฆ๐˜ด๐˜ด.๐˜ซ๐˜ด๐˜ฐ๐˜ฏ());

// ๐˜ˆ๐˜ต๐˜ต๐˜ข๐˜ค๐˜ฉ ๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต ๐˜๐˜‹ ๐˜ต๐˜ฐ ๐˜ฆ๐˜ท๐˜ฆ๐˜ณ๐˜บ ๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต
๐˜ข๐˜ฑ๐˜ฑ.๐˜ถ๐˜ด๐˜ฆ((๐˜ณ๐˜ฆ๐˜ฒ, ๐˜ณ๐˜ฆ๐˜ด, ๐˜ฏ๐˜ฆ๐˜น๐˜ต) => {
๐˜ค๐˜ฐ๐˜ฏ๐˜ด๐˜ต ๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ฅ = (๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฉ๐˜ฆ๐˜ข๐˜ฅ๐˜ฆ๐˜ณ๐˜ด['๐˜น-๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต-๐˜ช๐˜ฅ'] ๐˜ข๐˜ด ๐˜ด๐˜ต๐˜ณ๐˜ช๐˜ฏ๐˜จ) || ๐˜ณ๐˜ข๐˜ฏ๐˜ฅ๐˜ฐ๐˜ฎ๐˜œ๐˜œ๐˜๐˜‹();
๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฉ๐˜ฆ๐˜ข๐˜ฅ๐˜ฆ๐˜ณ๐˜ด['๐˜น-๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต-๐˜ช๐˜ฅ'] = ๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ฅ;
๐˜ณ๐˜ฆ๐˜ด.๐˜ด๐˜ฆ๐˜ต๐˜๐˜ฆ๐˜ข๐˜ฅ๐˜ฆ๐˜ณ('๐˜น-๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต-๐˜ช๐˜ฅ', ๐˜ณ๐˜ฆ๐˜ฒ๐˜ถ๐˜ฆ๐˜ด๐˜ต๐˜๐˜ฅ);
๐˜ฏ๐˜ฆ๐˜น๐˜ต();
});

// ๐˜™๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ด
๐˜ข๐˜ฑ๐˜ฑ.๐˜ถ๐˜ด๐˜ฆ('/๐˜ข๐˜ฑ๐˜ช/๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜ด', ๐˜ถ๐˜ด๐˜ฆ๐˜ณ๐˜™๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ด);

// 404 ๐˜ฉ๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ โ€” ๐˜ฎ๐˜ถ๐˜ด๐˜ต ๐˜ค๐˜ฐ๐˜ฎ๐˜ฆ ๐˜ข๐˜ง๐˜ต๐˜ฆ๐˜ณ ๐˜ข๐˜ญ๐˜ญ ๐˜ณ๐˜ฐ๐˜ถ๐˜ต๐˜ฆ๐˜ด
๐˜ข๐˜ฑ๐˜ฑ.๐˜ถ๐˜ด๐˜ฆ((๐˜ณ๐˜ฆ๐˜ฒ, ๐˜ณ๐˜ฆ๐˜ด, ๐˜ฏ๐˜ฆ๐˜น๐˜ต) => {
๐˜ฏ๐˜ฆ๐˜น๐˜ต(๐˜ฏ๐˜ฆ๐˜ธ ๐˜•๐˜ฐ๐˜ต๐˜๐˜ฐ๐˜ถ๐˜ฏ๐˜ฅ๐˜Œ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ(๐˜™๐˜ฐ๐˜ถ๐˜ต๐˜ฆ ${๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฎ๐˜ฆ๐˜ต๐˜ฉ๐˜ฐ๐˜ฅ} ${๐˜ณ๐˜ฆ๐˜ฒ.๐˜ฑ๐˜ข๐˜ต๐˜ฉ}));
});

// ๐˜Š๐˜ฆ๐˜ฏ๐˜ต๐˜ณ๐˜ข๐˜ญ ๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ ๐˜ฉ๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ โ€” ๐˜ฎ๐˜ถ๐˜ด๐˜ต ๐˜ฃ๐˜ฆ ๐˜ญ๐˜ข๐˜ด๐˜ต, ๐˜ฎ๐˜ถ๐˜ด๐˜ต ๐˜ฉ๐˜ข๐˜ท๐˜ฆ 4 ๐˜ฑ๐˜ข๐˜ณ๐˜ข๐˜ฎ๐˜ด
๐˜ข๐˜ฑ๐˜ฑ.๐˜ถ๐˜ด๐˜ฆ(๐˜ฆ๐˜ณ๐˜ณ๐˜ฐ๐˜ณ๐˜๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ณ);

๐˜ฆ๐˜น๐˜ฑ๐˜ฐ๐˜ณ๐˜ต ๐˜ฅ๐˜ฆ๐˜ง๐˜ข๐˜ถ๐˜ญ๐˜ต ๐˜ข๐˜ฑ๐˜ฑ;

The order matters. The errorHandler must be registered last. The 404 handler must come after all your routes. The request ID middleware must come first so every log line has it.


๐—ช๐—ต๐—ฎ๐˜ ๐˜๐—ต๐—ถ๐˜€ ๐—ด๐—ถ๐˜ƒ๐—ฒ๐˜€ ๐˜†๐—ผ๐˜‚ ๐—ถ๐—ป ๐—ฝ๐—ฟ๐—ผ๐—ฑ๐˜‚๐—ฐ๐˜๐—ถ๐—ผ๐—ป

Every error in your API now has:
โ€ข A typed code field clients can handle programmatically (NOT_FOUND, UNAUTHORIZED, VALIDATION_ERROR)

โ€ข A clean message safe to show users

โ€ข A requestId that ties logs across every layer

โ€ข Full stack traces in logs for unexpected failures

โ€ข Zero internal detail leaked to the outside world

When something breaks at 2am, you grep the requestId from the client's error response and pull the full picture from your logs in seconds โ€” not hours.

๐‘ ๐‘Ÿ๐‘/
โ”œโ”€โ”€ ๐‘’๐‘Ÿ๐‘Ÿ๐‘œ๐‘Ÿ๐‘ /
โ”‚ โ””โ”€โ”€ ๐ด๐‘๐‘๐ธ๐‘Ÿ๐‘Ÿ๐‘œ๐‘Ÿ.๐‘ก๐‘  # ๐‘ก๐‘ฆ๐‘๐‘’๐‘‘ ๐‘’๐‘Ÿ๐‘Ÿ๐‘œ๐‘Ÿ ๐‘๐‘™๐‘Ž๐‘ ๐‘ ๐‘’๐‘ 
โ”œโ”€โ”€ ๐‘š๐‘–๐‘‘๐‘‘๐‘™๐‘’๐‘ค๐‘Ž๐‘Ÿ๐‘’/
โ”‚ โ””โ”€โ”€ ๐‘’๐‘Ÿ๐‘Ÿ๐‘œ๐‘Ÿ๐ป๐‘Ž๐‘›๐‘‘๐‘™๐‘’๐‘Ÿ.๐‘ก๐‘  # ๐‘๐‘’๐‘›๐‘ก๐‘Ÿ๐‘Ž๐‘™ ๐‘’๐‘Ÿ๐‘Ÿ๐‘œ๐‘Ÿ โ„Ž๐‘Ž๐‘›๐‘‘๐‘™๐‘’๐‘Ÿ
โ”œโ”€โ”€ ๐‘ข๐‘ก๐‘–๐‘™๐‘ /
โ”‚ โ””โ”€โ”€ ๐‘Ž๐‘ ๐‘ฆ๐‘›๐‘๐ป๐‘Ž๐‘›๐‘‘๐‘™๐‘’๐‘Ÿ.๐‘ก๐‘  # ๐‘Ž๐‘ ๐‘ฆ๐‘›๐‘ ๐‘Ÿ๐‘œ๐‘ข๐‘ก๐‘’ ๐‘ค๐‘Ÿ๐‘Ž๐‘๐‘๐‘’๐‘Ÿ
โ”œโ”€โ”€ ๐‘Ÿ๐‘œ๐‘ข๐‘ก๐‘’๐‘ /
โ”‚ โ””โ”€โ”€ ๐‘ข๐‘ ๐‘’๐‘Ÿ๐‘ .๐‘ก๐‘  # ๐‘๐‘™๐‘’๐‘Ž๐‘› ๐‘Ÿ๐‘œ๐‘ข๐‘ก๐‘’๐‘ , ๐‘›๐‘œ ๐‘ก๐‘Ÿ๐‘ฆ/๐‘๐‘Ž๐‘ก๐‘โ„Ž
โ””โ”€โ”€ ๐‘Ž๐‘๐‘.๐‘ก๐‘  # ๐‘ค๐‘–๐‘Ÿ๐‘’๐‘‘ ๐‘ก๐‘œ๐‘”๐‘’๐‘กโ„Ž๐‘’๐‘Ÿ


๐—ข๐—ป๐—ฒ ๐˜๐—ต๐—ถ๐—ป๐—ด ๐˜๐—ผ ๐—ฎ๐—ฑ๐—ฑ ๐—ป๐—ฒ๐˜…๐˜

If you want to go further, add a process-level handler for truly unexpected crashes:

// ๐˜ด๐˜ณ๐˜ค/๐˜ด๐˜ฆ๐˜ณ๐˜ท๐˜ฆ๐˜ณ.๐˜ต๐˜ด
๐˜ฑ๐˜ณ๐˜ฐ๐˜ค๐˜ฆ๐˜ด๐˜ด.๐˜ฐ๐˜ฏ('๐˜ถ๐˜ฏ๐˜ค๐˜ข๐˜ถ๐˜จ๐˜ฉ๐˜ต๐˜Œ๐˜น๐˜ค๐˜ฆ๐˜ฑ๐˜ต๐˜ช๐˜ฐ๐˜ฏ', (๐˜ฆ๐˜ณ๐˜ณ) => {
๐˜ญ๐˜ฐ๐˜จ๐˜จ๐˜ฆ๐˜ณ.๐˜ง๐˜ข๐˜ต๐˜ข๐˜ญ({ ๐˜ฆ๐˜ณ๐˜ณ }, '๐˜œ๐˜ฏ๐˜ค๐˜ข๐˜ถ๐˜จ๐˜ฉ๐˜ต ๐˜ฆ๐˜น๐˜ค๐˜ฆ๐˜ฑ๐˜ต๐˜ช๐˜ฐ๐˜ฏ โ€” ๐˜ด๐˜ฉ๐˜ถ๐˜ต๐˜ต๐˜ช๐˜ฏ๐˜จ ๐˜ฅ๐˜ฐ๐˜ธ๐˜ฏ');
๐˜ฑ๐˜ณ๐˜ฐ๐˜ค๐˜ฆ๐˜ด๐˜ด.๐˜ฆ๐˜น๐˜ช๐˜ต(1);
});

๐˜ฑ๐˜ณ๐˜ฐ๐˜ค๐˜ฆ๐˜ด๐˜ด.๐˜ฐ๐˜ฏ('๐˜ถ๐˜ฏ๐˜ฉ๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ฅ๐˜™๐˜ฆ๐˜ซ๐˜ฆ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ', (๐˜ณ๐˜ฆ๐˜ข๐˜ด๐˜ฐ๐˜ฏ) => {
๐˜ญ๐˜ฐ๐˜จ๐˜จ๐˜ฆ๐˜ณ.๐˜ง๐˜ข๐˜ต๐˜ข๐˜ญ({ ๐˜ณ๐˜ฆ๐˜ข๐˜ด๐˜ฐ๐˜ฏ }, '๐˜œ๐˜ฏ๐˜ฉ๐˜ข๐˜ฏ๐˜ฅ๐˜ญ๐˜ฆ๐˜ฅ ๐˜ณ๐˜ฆ๐˜ซ๐˜ฆ๐˜ค๐˜ต๐˜ช๐˜ฐ๐˜ฏ โ€” ๐˜ด๐˜ฉ๐˜ถ๐˜ต๐˜ต๐˜ช๐˜ฏ๐˜จ ๐˜ฅ๐˜ฐ๐˜ธ๐˜ฏ');
๐˜ฑ๐˜ณ๐˜ฐ๐˜ค๐˜ฆ๐˜ด๐˜ด.๐˜ฆ๐˜น๐˜ช๐˜ต(1);
});


Fail fast. Fail loud. Let your process manager (PM2, Docker, Kubernetes) restart the service. Never let your app limp along in a broken state.
This pattern takes about 20 minutes to wire up on a new project. It has saved me hours of debugging on every project since.


If you're building a REST API in Express + TypeScript and you don't have something like this in place โ€” start here before you add another feature.


๐ด๐‘Ÿ๐‘’ ๐‘ฆ๐‘œ๐‘ข ๐‘ข๐‘ ๐‘–๐‘›๐‘” ๐‘Ž ๐‘‘๐‘–๐‘“๐‘“๐‘’๐‘Ÿ๐‘’๐‘›๐‘ก ๐‘’๐‘Ÿ๐‘Ÿ๐‘œ๐‘Ÿ โ„Ž๐‘Ž๐‘›๐‘‘๐‘™๐‘–๐‘›๐‘” ๐‘๐‘Ž๐‘ก๐‘ก๐‘’๐‘Ÿ๐‘› ๐‘–๐‘› ๐‘๐‘Ÿ๐‘œ๐‘‘๐‘ข๐‘๐‘ก๐‘–๐‘œ๐‘›? ๐‘†๐‘œ๐‘š๐‘’๐‘กโ„Ž๐‘–๐‘›๐‘” ๐‘ฆ๐‘œ๐‘ข'๐‘‘ ๐‘Ž๐‘‘๐‘‘ ๐‘œ๐‘Ÿ ๐‘โ„Ž๐‘Ž๐‘›๐‘”๐‘’ โ„Ž๐‘’๐‘Ÿ๐‘’? ๐ท๐‘Ÿ๐‘œ๐‘ ๐‘–๐‘ก ๐‘–๐‘› ๐‘กโ„Ž๐‘’ ๐‘๐‘œ๐‘š๐‘š๐‘’๐‘›๐‘ก๐‘  โ€” ๐ผ'๐‘š ๐‘”๐‘’๐‘›๐‘ข๐‘–๐‘›๐‘’๐‘™๐‘ฆ ๐‘๐‘ข๐‘Ÿ๐‘–๐‘œ๐‘ข๐‘  ๐‘คโ„Ž๐‘Ž๐‘ก ๐‘œ๐‘กโ„Ž๐‘’๐‘Ÿ๐‘  โ„Ž๐‘Ž๐‘ฃ๐‘’ ๐‘™๐‘Ž๐‘›๐‘‘๐‘’๐‘‘ ๐‘œ๐‘›.

Top comments (0)