@prefabs.tech/fastify-error-handler
v0.94.1
Published
Fastify error-handler plugin
Downloads
1,641
Keywords
Readme
@prefabs.tech/fastify-error-handler
A Fastify plugin that provides a standardized, production-safe global error handler for APIs.
Why This Plugin?
In a large API or microservice ecosystem, inconsistent error handling quickly leads to bloated controllers and unpredictable API responses for your frontend clients. We created this plugin to:
- Unify Your Error Responses: By providing a global error formatter powered by
@fastify/sensible, we ensure that no matter where an error originates — a database crash, a validation failure, or a manual throw — your API always responds with a standardized, predictable JSON shape. - Keep Controllers Clean: We enforce an exceptions-based approach. Focus purely on the happy path in your route handlers. Instead of manually catching errors and calling
reply.code(400).send(...), you simplythrowan error and let the global handler manage the rest. - Provide Safe Interception: Fastify only allows one global
setErrorHandler. If you use libraries like SuperTokens that require their own error handling, standard setups break. We designed a cleanpreErrorHandleroption to let you safely run those third-party hooks before falling back to the standard global formatter. - Standardize Custom Exceptions: We provide a strongly-typed
CustomErrorbase class so you can attach specific application error codes and metadata across your monorepo without resorting to raw strings or plainErrorobjects.
What You Get
@fastify/sensible — Full Passthrough
All options from @fastify/sensible are supported. This plugin registers it internally with no configuration, exposing fastify.httpErrors.* helpers on the instance.
Added by This Plugin
- Global error handler — catches all thrown errors (HttpErrors, CustomErrors, plain Errors, and non-Error values) and formats them into a consistent
ErrorResponseJSON shape - Safe message masking — 5xx errors hide implementation details behind generic messages by default;
stackTrace: truedisables masking for development preErrorHandlerhook — run custom logic (e.g. SuperTokens, Passport) before the default handler; short-circuits if your handler sends the reply, swallows exceptions otherwiseCustomErrorbase class — extend it to create domain errors with a customcodefield; subclasses are handled safelystackTraceoption — controls whether parsed stack frames are included in error responsesErrorResponseJSON schema — registered as$id: "ErrorResponse"for use in route response schemas via$ref: "ErrorResponse#"- Severity-aware logging — 4xx errors log at
info, 5xx aterror; non-Error thrown values are normalized and logged safely domainErrorStatusMap— optional app-providedMap<string, number>fromerror.nameto an HTTP status integer400–599(invalid entries fail at registration); the plugin stores a validated copy. Mapped errors return that status with message/name (andCustomErrorcode) in the body—only unmapped non-HttpErrorerrors use generic masking whenstackTraceis false
→ Full feature list · Developer guide
Usage Guidelines
Controllers must not reply with non-200 responses
Do not manually send error responses from route handlers. Always throw and let the global error handler format the response.
Wrong
fastify.get("/test", async (req, reply) => {
return reply.code(401).send({ message: "Unauthorized" });
});Correct
fastify.get("/test", async () => {
throw fastify.httpErrors.unauthorized("Unauthorized");
});Throw CustomError (or a subclass) for domain errors
Modules must throw an instance of CustomError (or a class extending it) for application-level errors. This ensures errors are caught consistently and the correct action can be taken.
import { CustomError } from "@prefabs.tech/fastify-error-handler";
const file = await fileService.findById(id);
if (!file) {
throw new CustomError("File not found", "FILE_NOT_FOUND_ERROR");
}Requirements
Peer dependencies (must be installed separately):
fastify>=5.2.1fastify-plugin>=5.0.1
Register this plugin before all routes and other plugins so the error handler is in place for the entire application.
Quick Start
import errorHandlerPlugin from "@prefabs.tech/fastify-error-handler";
import Fastify from "fastify";
const fastify = Fastify();
await fastify.register(errorHandlerPlugin, {
stackTrace: process.env.NODE_ENV === "development",
});
// Throw errors in routes — the handler does the rest
fastify.get("/example", async () => {
throw fastify.httpErrors.notFound("Resource not found");
});
await fastify.listen({ port: 3000, host: "0.0.0.0" });Domain status codes
Use domainErrorStatusMap when domain errors should return non-500 statuses — pass a Map whose keys match thrown error.name; each value must be an integer 400–599. Mapped responses include the thrown message and name (and CustomError codes); generic masking applies only to unmapped internal errors when stackTrace is off.
await fastify.register(errorHandlerPlugin, {
domainErrorStatusMap: new Map([["UnprocessableEntityError", 422]]),
});Standalone errorHandler usage
If you use the exported errorHandler directly (without registering the plugin), pass options as the 4th argument:
import { errorHandler } from "@prefabs.tech/fastify-error-handler";
fastify.setErrorHandler((error, request, reply) => {
return errorHandler(error, request, reply, {
stackTrace: true,
domainErrorStatusMap: new Map([["UnprocessableEntityError", 422]]),
});
});Installation
Install with npm:
npm install @prefabs.tech/fastify-error-handlerInstall with pnpm:
pnpm add @prefabs.tech/fastify-error-handler