not sure why those errors got removed we'll see
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 12m30s

This commit is contained in:
2025-12-26 08:43:49 -08:00
parent aefd57e57b
commit 91fa2f0516
2 changed files with 72 additions and 47 deletions

View File

@@ -1,5 +1,6 @@
// src/middleware/errorHandler.ts
import { Request, Response, NextFunction } from 'express';
import crypto from 'crypto';
import { ZodError } from 'zod';
import {
ForeignKeyConstraintError,
@@ -24,45 +25,73 @@ export const errorHandler = (err: Error, req: Request, res: Response, next: Next
// Use the request-scoped logger if available, otherwise fall back to the global logger.
const log = req.log || logger;
// --- Handle Zod Validation Errors ---
// --- Handle Zod Validation Errors (from validateRequest middleware) ---
if (err instanceof ZodError) {
log.warn({ err: err.flatten() }, 'Request validation failed');
return res.status(400).json({
message: 'The request data is invalid.',
errors: err.issues.map((e) => ({ path: e.path, message: e.message })),
});
const statusCode = 400;
const message = 'The request data is invalid.';
const errors = err.issues.map((e) => ({ path: e.path, message: e.message }));
log.warn({ err, validationErrors: errors, statusCode }, `Client Error on ${req.method} ${req.path}: ${message}`);
return res.status(statusCode).json({ message, errors });
}
// --- Handle Custom Operational Errors ---
if (err instanceof NotFoundError) {
log.info({ err }, 'Resource not found');
return res.status(404).json({ message: err.message });
const statusCode = 404;
log.warn({ err, statusCode }, `Client Error on ${req.method} ${req.path}: ${err.message}`);
return res.status(statusCode).json({ message: err.message });
}
if (err instanceof ValidationError) {
log.warn({ err }, 'Validation error occurred');
return res.status(400).json({ message: err.message, errors: err.validationErrors });
const statusCode = 400;
log.warn(
{ err, validationErrors: err.validationErrors, statusCode },
`Client Error on ${req.method} ${req.path}: ${err.message}`,
);
return res.status(statusCode).json({ message: err.message, errors: err.validationErrors });
}
if (err instanceof UniqueConstraintError) {
log.warn({ err }, 'Constraint error occurred');
return res.status(409).json({ message: err.message }); // Use 409 Conflict for unique constraints
const statusCode = 409;
log.warn({ err, statusCode }, `Client Error on ${req.method} ${req.path}: ${err.message}`);
return res.status(statusCode).json({ message: err.message }); // Use 409 Conflict for unique constraints
}
if (err instanceof ForeignKeyConstraintError) {
log.warn({ err }, 'Foreign key constraint violation');
return res.status(400).json({ message: err.message });
const statusCode = 400;
log.warn({ err, statusCode }, `Client Error on ${req.method} ${req.path}: ${err.message}`);
return res.status(statusCode).json({ message: err.message });
}
// --- Handle Generic Errors ---
// Log the full error object for debugging. The pino logger will handle redaction.
log.error({ err }, 'An unhandled error occurred in an Express route');
// --- Handle Generic Client Errors (e.g., from express-jwt, or manual status setting) ---
const status = (err as any).status || (err as any).statusCode;
if (status && status >= 400 && status < 500) {
log.warn({ err, statusCode: status }, `Client Error on ${req.method} ${req.path}: ${err.message}`);
return res.status(status).json({ message: err.message });
}
// --- Handle All Other (500-level) Errors ---
const errorId = crypto.randomBytes(4).toString('hex');
log.error(
{
err,
errorId,
req: { method: req.method, url: req.url, headers: req.headers, body: req.body },
},
`Unhandled API Error (ID: ${errorId})`,
);
// Also log to console in test environment for visibility in test runners
if (process.env.NODE_ENV === 'test') {
console.error(`--- [TEST] UNHANDLED ERROR (ID: ${errorId}) ---`, err);
}
// In production, send a generic message to avoid leaking implementation details.
if (process.env.NODE_ENV === 'production') {
return res.status(500).json({ message: 'An internal server error occurred.' });
return res.status(500).json({
message: `An unexpected server error occurred. Please reference error ID: ${errorId}`,
});
}
// In non-production environments (dev, test, etc.), send more details for easier debugging.
return res.status(500).json({ message: err.message, stack: err.stack });
return res.status(500).json({ message: err.message, stack: err.stack, errorId });
};