Fast and low overhead web framework for Node.js with powerful plugin architecture
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Comprehensive error handling system with custom error handlers and built-in error types.
Set custom error handlers for application-wide error processing.
/**
* Set custom error handler for all unhandled errors
* @param handler - Error handling function
* @returns FastifyInstance for method chaining
*/
setErrorHandler(handler: (
error: FastifyError,
request: FastifyRequest,
reply: FastifyReply
) => void | Promise<void>): FastifyInstance;Usage Examples:
// Basic error handler
fastify.setErrorHandler((error, request, reply) => {
// Log error
request.log.error(error);
// Send appropriate response
if (error.statusCode) {
reply.status(error.statusCode).send({
error: error.name,
message: error.message
});
} else {
reply.status(500).send({
error: 'Internal Server Error',
message: 'Something went wrong'
});
}
});
// Async error handler with custom logic
fastify.setErrorHandler(async (error, request, reply) => {
// Record error in monitoring system
await errorTracker.recordError(error, {
requestId: request.id,
userId: request.user?.id,
route: request.routerPath
});
// Handle different error types
if (error.code === 'FST_ERR_VALIDATION') {
reply.status(400).send({
error: 'Validation Error',
details: error.validation
});
} else if (error.statusCode === 404) {
reply.status(404).send({
error: 'Not Found',
message: 'The requested resource was not found'
});
} else {
reply.status(500).send({
error: 'Internal Server Error',
message: process.env.NODE_ENV === 'production'
? 'Something went wrong'
: error.message
});
}
});Handle 404 errors with custom logic.
/**
* Set custom handler for 404 Not Found errors
* @param handler - Not found handling function
* @returns FastifyInstance for method chaining
*/
setNotFoundHandler(handler: (
request: FastifyRequest,
reply: FastifyReply
) => void | Promise<void>): FastifyInstance;
/**
* Set not found handler with options
* @param options - Handler configuration options
* @param handler - Not found handling function
* @returns FastifyInstance for method chaining
*/
setNotFoundHandler(
options: {
preValidation?: Function | Function[];
preHandler?: Function | Function[];
},
handler: (request: FastifyRequest, reply: FastifyReply) => void | Promise<void>
): FastifyInstance;Usage Examples:
// Basic 404 handler
fastify.setNotFoundHandler((request, reply) => {
reply.code(404).send({
error: 'Not Found',
message: `Route ${request.method} ${request.url} not found`,
statusCode: 404
});
});
// 404 handler with custom logic
fastify.setNotFoundHandler(async (request, reply) => {
// Log 404s for analytics
request.log.warn(`404: ${request.method} ${request.url}`);
// Try to suggest similar routes
const suggestions = await findSimilarRoutes(request.url);
reply.code(404).send({
error: 'Not Found',
message: `Route ${request.url} not found`,
suggestions: suggestions.length > 0 ? suggestions : undefined
});
});
// 404 handler with preprocessing
fastify.setNotFoundHandler({
preValidation: (request, reply, done) => {
// Rate limit 404 requests
const key = `404_${request.ip}`;
rateLimiter.check(key, (err, allowed) => {
if (!allowed) {
reply.code(429).send({ error: 'Too Many Requests' });
return;
}
done();
});
}
}, (request, reply) => {
reply.code(404).send({ error: 'Not Found' });
});Understanding Fastify's built-in error types and creating custom errors.
/**
* Base Fastify error interface
*/
interface FastifyError extends Error {
name: string;
message: string;
code: string;
statusCode?: number;
validation?: FastifySchemaValidationError[];
validationContext?: string;
}Common Error Codes:
// Built-in Fastify error codes
const errorCodes = {
FST_ERR_VALIDATION: 'Request validation failed',
FST_ERR_INVALID_URL: 'Invalid URL',
FST_ERR_ROUTE_ALREADY_EXISTS: 'Route already exists',
FST_ERR_PLUGIN_NOT_VALID: 'Plugin is not valid',
FST_ERR_HOOK_INVALID_TYPE: 'Hook type is invalid',
FST_ERR_HOOK_INVALID_HANDLER: 'Hook handler is invalid',
FST_ERR_INSTANCE_ALREADY_LISTENING: 'Instance is already listening',
// ... many more
};
// Access error codes
const { FST_ERR_VALIDATION } = require('fastify').errorCodes;Create and throw custom errors with proper status codes.
// Using @fastify/error for custom errors
const createError = require('@fastify/error');
// Define custom error types
const ValidationError = createError('VALIDATION_ERROR', 'Validation failed: %s', 400);
const AuthorizationError = createError('AUTHORIZATION_ERROR', 'Access denied: %s', 403);
const NotFoundError = createError('NOT_FOUND_ERROR', 'Resource not found: %s', 404);
// Use in route handlers
fastify.get('/users/:id', async (request, reply) => {
const user = await findUser(request.params.id);
if (!user) {
throw new NotFoundError('User not found');
}
return user;
});
// Use in hooks
fastify.addHook('preHandler', async (request, reply) => {
if (!request.user) {
throw new AuthorizationError('Authentication required');
}
if (!request.user.active) {
throw new AuthorizationError('Account is disabled');
}
});Error handlers can be scoped to specific plugin contexts.
// Global error handler
fastify.setErrorHandler((error, request, reply) => {
request.log.error(error, 'Global error handler');
reply.status(500).send({ error: 'Internal Server Error' });
});
// Plugin-scoped error handler
await fastify.register(async function (fastify) {
// This error handler only applies to routes in this plugin
fastify.setErrorHandler((error, request, reply) => {
request.log.error(error, 'Plugin error handler');
if (error.code === 'PLUGIN_SPECIFIC_ERROR') {
reply.status(422).send({ error: 'Plugin specific error' });
} else {
// Forward to parent error handler
throw error;
}
});
fastify.get('/plugin-route', handler);
});Handle schema validation errors specifically.
// Custom validation error handling
fastify.setErrorHandler((error, request, reply) => {
if (error.code === 'FST_ERR_VALIDATION') {
const validationErrors = error.validation.map(err => ({
field: err.instancePath || err.schemaPath,
message: err.message,
value: err.data
}));
reply.status(400).send({
error: 'Validation Error',
message: 'Request validation failed',
details: validationErrors
});
return;
}
// Handle other errors
reply.status(error.statusCode || 500).send({
error: error.name || 'Error',
message: error.message
});
});
// Using attachValidation for manual handling
fastify.post('/users', {
attachValidation: true,
schema: { body: userSchema }
}, async (request, reply) => {
if (request.validationError) {
// Custom validation error response
reply.status(400).send({
success: false,
error: 'Invalid user data',
fields: request.validationError.validation.map(err => ({
name: err.instancePath.replace('/', ''),
message: err.message
}))
});
return;
}
const user = await createUser(request.body);
reply.status(201).send({ success: true, user });
});Enhance error handling with context and structured logging.
// Enhanced error handler with context
fastify.setErrorHandler(async (error, request, reply) => {
const errorContext = {
requestId: request.id,
method: request.method,
url: request.url,
userAgent: request.headers['user-agent'],
ip: request.ip,
userId: request.user?.id,
timestamp: new Date().toISOString(),
stack: error.stack
};
// Structured error logging
request.log.error({
err: error,
context: errorContext
}, 'Request error occurred');
// Send to external error tracking
if (process.env.NODE_ENV === 'production') {
await errorTracker.capture(error, errorContext);
}
// Send appropriate response
const isDevelopment = process.env.NODE_ENV === 'development';
reply.status(error.statusCode || 500).send({
error: error.name || 'Error',
message: error.message,
...(isDevelopment && { stack: error.stack }),
requestId: request.id
});
});Handle framework-level errors that occur outside normal request processing.
// Framework error handler (set in options)
const fastify = require('fastify')({
frameworkErrors: (error, request, reply) => {
// Handle framework-level errors (e.g., malformed JSON)
if (error.type === 'entity.parse.failed') {
reply.status(400).send({
error: 'Bad Request',
message: 'Invalid JSON in request body'
});
} else {
reply.status(500).send({
error: 'Framework Error',
message: 'A framework-level error occurred'
});
}
}
});