Overview
Centralized error handling for your Fastify app. Includes custom error classes for common HTTP errors.
Features
- Global error catching
- Custom error classes
- Environment-aware responses
- Request ID inclusion
- Not found handler
Installation
npx hanma add fastify-error-handler --framework fastify
Dependencies
fastify
Code
import { FastifyInstance, FastifyRequest, FastifyReply, FastifyError } from "fastify";
/**
* Custom application error class
*/
export class AppError extends Error {
public readonly statusCode: number;
public readonly code: string;
public readonly isOperational: boolean;
public readonly details?: unknown;
constructor(
message: string,
statusCode = 500,
code = "INTERNAL_ERROR",
details?: unknown
) {
super(message);
this.name = "AppError";
this.statusCode = statusCode;
this.code = code;
this.isOperational = true;
this.details = details;
Error.captureStackTrace(this, this.constructor);
}
}
/**
* Common error types
*/
export class NotFoundError extends AppError {
constructor(resource = "Resource", details?: unknown) {
super(`${resource} not found`, 404, "NOT_FOUND", details);
}
}
export class ValidationError extends AppError {
constructor(message = "Validation failed", details?: unknown) {
super(message, 400, "VALIDATION_ERROR", details);
}
}
export class UnauthorizedError extends AppError {
constructor(message = "Authentication required", details?: unknown) {
super(message, 401, "UNAUTHORIZED", details);
}
}
export class ForbiddenError extends AppError {
constructor(message = "Access denied", details?: unknown) {
super(message, 403, "FORBIDDEN", details);
}
}
export class ConflictError extends AppError {
constructor(message = "Resource conflict", details?: unknown) {
super(message, 409, "CONFLICT", details);
}
}
export class RateLimitError extends AppError {
constructor(retryAfter?: number) {
super("Rate limit exceeded", 429, "RATE_LIMIT_EXCEEDED", { retryAfter });
}
}
/**
* Error response format
*/
interface ErrorResponse {
success: false;
error: {
code: string;
message: string;
details?: unknown;
stack?: string;
};
requestId?: string;
}
/**
* Register global error handler
*/
export function registerErrorHandler(app: FastifyInstance): void {
const isDev = process.env.NODE_ENV === "development";
app.setErrorHandler((error: FastifyError, request: FastifyRequest, reply: FastifyReply) => {
// Log the error
if (error instanceof AppError && error.isOperational) {
request.log.warn({ error, requestId: request.id }, error.message);
} else {
request.log.error({ error, requestId: request.id }, "Unexpected error");
}
// Build response
const response: ErrorResponse = {
success: false,
error: {
code: (error as AppError).code ?? "INTERNAL_ERROR",
message: error.message,
details: (error as AppError).details,
stack: isDev ? error.stack : undefined,
},
requestId: request.id,
};
// Determine status code
const statusCode =
(error as AppError).statusCode ??
error.statusCode ??
500;
// Handle specific Fastify errors
if (error.validation) {
response.error.code = "VALIDATION_ERROR";
response.error.details = error.validation;
reply.status(400).send(response);
return;
}
// Don't expose internal error details in production
if (statusCode >= 500 && !isDev) {
response.error.message = "Internal server error";
delete response.error.details;
}
reply.status(statusCode).send(response);
});
// 404 handler
app.setNotFoundHandler((request: FastifyRequest, reply: FastifyReply) => {
reply.status(404).send({
success: false,
error: {
code: "NOT_FOUND",
message: "Route not found",
details: {
method: request.method,
path: request.url,
},
},
requestId: request.id,
});
});
}
// Usage:
// registerErrorHandler(app);
// throw new NotFoundError("User");
// throw new ValidationError("Email is required", { field: "email" });
Usage
import { registerErrorHandler, NotFoundError, ValidationError } from './middleware/error-handler';
registerErrorHandler(app);
// Throw custom errors
throw new NotFoundError('User');
throw new ValidationError('Email is required', { field: 'email' });
Dependencies
fastify
Frequently Asked Questions
How do I install Error Handler?
Run the following command:
npx hanma add fastify-error-handler --framework fastifyWhat dependencies are required?
This snippet requires: fastify. Make sure to install them before using the snippet.
How do I use this snippet?
Copy the code and paste it into your project. The snippet will be saved to
src/middleware/error-handler.ts.Can I customize this snippet?
Yes! All snippets are copy-paste code that you own. Feel free to modify them to fit your needs.
Does this work with other frameworks?
This snippet is designed for the specific framework. Check the other framework pages for equivalent implementations.