Skip to content

Handling Errors

Route errors with composable handlers or a reusable handler class.

nice-code offers two handling styles: a composable functional API, and a reusable class.

Build a list of cases with forId, forIds, and forDomain. handleWithSync runs the first matching case and returns whether anything handled it.

import { forDomain, forId, forIds } from "@nice-code/error";
const handled = error.handleWithSync([
forId(err_auth, "invalid_credentials", (h) => {
const { username } = h.getContext("invalid_credentials");
return res.status(401).json({ error: `Bad credentials for ${username}` });
}),
forIds(err_auth, ["account_locked", "rate_limited"], (h) => {
return res.status(h.httpStatusCode).json({ error: h.message });
}),
forDomain(err_payment, (h) => {
return res.status(500).json({ error: "Payment failed" });
}),
]);

The handler argument (h) is narrowed to the matched id(s), so getContext is typed inside each case.

await error.handleWithAsync([
forDomain(err_payment, async (h) => {
await db.logFailure(h.message);
await notify(h.toJsonObject());
}),
]);

NiceErrorHandler is a reusable handler you configure once and apply to many errors — ideal for a central error boundary.

import { NiceErrorHandler } from "@nice-code/error";
const handler = new NiceErrorHandler()
.forId(err_auth, "invalid_credentials", (h) => "unauthorized")
.forDomain(err_payment, (h) => "payment_error")
.setDefaultHandler((e) => "unknown_error");
handler.handleErrorWithPromiseInspection(error);
  • Functional — local, one-off routing inside a single catch block.
  • Class-based — a shared, reusable policy you register once (server middleware, a global boundary).

Next: Results & Observability →