Spaces:
Runtime error
Runtime error
| import { ZodError } from 'zod'; | |
| import logger from '../utils/logger.js'; | |
| /** | |
| * Centralized error handling middleware | |
| * Must be registered LAST in the Express middleware chain | |
| */ | |
| export const errorHandler = (err, req, res, _next) => { | |
| // Log the error | |
| logger.error('Unhandled error', { | |
| message: err.message, | |
| stack: process.env.NODE_ENV === 'development' ? err.stack : undefined, | |
| method: req.method, | |
| url: req.url, | |
| ip: req.ip, | |
| }); | |
| // Handle Zod validation errors | |
| if (err instanceof ZodError) { | |
| return res.status(400).json({ | |
| success: false, | |
| error: 'Validation failed', | |
| details: err.errors.map((e) => ({ | |
| field: e.path.join('.'), | |
| message: e.message, | |
| })), | |
| }); | |
| } | |
| // Prisma known errors | |
| if (err.code === 'P2002') { | |
| return res.status(409).json({ | |
| success: false, | |
| error: 'A record with this information already exists.', | |
| field: err.meta?.target?.[0], | |
| }); | |
| } | |
| if (err.code === 'P2025') { | |
| return res.status(404).json({ | |
| success: false, | |
| error: 'Record not found.', | |
| }); | |
| } | |
| if (err.code === 'P2003') { | |
| return res.status(400).json({ | |
| success: false, | |
| error: 'Invalid reference. The related record does not exist.', | |
| }); | |
| } | |
| // Generic HTTP errors | |
| const statusCode = err.statusCode || err.status || 500; | |
| const message = | |
| statusCode < 500 || process.env.NODE_ENV === 'development' | |
| ? err.message | |
| : 'An internal server error occurred. Please try again later.'; | |
| res.status(statusCode).json({ | |
| success: false, | |
| error: message, | |
| ...(process.env.NODE_ENV === 'development' && { stack: err.stack }), | |
| }); | |
| }; | |
| /** | |
| * 404 Not Found handler | |
| */ | |
| export const notFoundHandler = (req, res) => { | |
| res.status(404).json({ | |
| success: false, | |
| error: `Route not found: ${req.method} ${req.path}`, | |
| }); | |
| }; | |
| /** | |
| * Create a custom HTTP error | |
| */ | |
| export class AppError extends Error { | |
| constructor(message, statusCode = 500) { | |
| super(message); | |
| this.statusCode = statusCode; | |
| this.name = 'AppError'; | |
| Error.captureStackTrace(this, this.constructor); | |
| } | |
| } | |