fix(server): attach raw Error to res.err and avoid pino err key collision
Extract attachErrorContext helper to DRY up the error handler, attach the original Error object to res.err so pino can serialize stack traces, and rename the log context key from err to errorContext so it doesn't clash with pino's built-in err serializer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,25 @@ export interface ErrorContext {
|
||||
reqQuery?: unknown;
|
||||
}
|
||||
|
||||
function attachErrorContext(
|
||||
req: Request,
|
||||
res: Response,
|
||||
payload: ErrorContext["error"],
|
||||
rawError?: Error,
|
||||
) {
|
||||
(res as any).__errorContext = {
|
||||
error: payload,
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
reqBody: req.body,
|
||||
reqParams: req.params,
|
||||
reqQuery: req.query,
|
||||
} satisfies ErrorContext;
|
||||
if (rawError) {
|
||||
(res as any).err = rawError;
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandler(
|
||||
err: unknown,
|
||||
req: Request,
|
||||
@@ -19,14 +38,12 @@ export function errorHandler(
|
||||
) {
|
||||
if (err instanceof HttpError) {
|
||||
if (err.status >= 500) {
|
||||
(res as any).__errorContext = {
|
||||
error: { message: err.message, stack: err.stack, name: err.name, details: err.details },
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
reqBody: req.body,
|
||||
reqParams: req.params,
|
||||
reqQuery: req.query,
|
||||
} satisfies ErrorContext;
|
||||
attachErrorContext(
|
||||
req,
|
||||
res,
|
||||
{ message: err.message, stack: err.stack, name: err.name, details: err.details },
|
||||
err,
|
||||
);
|
||||
}
|
||||
res.status(err.status).json({
|
||||
error: err.message,
|
||||
@@ -40,16 +57,15 @@ export function errorHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
(res as any).__errorContext = {
|
||||
error: err instanceof Error
|
||||
const rootError = err instanceof Error ? err : new Error(String(err));
|
||||
attachErrorContext(
|
||||
req,
|
||||
res,
|
||||
err instanceof Error
|
||||
? { message: err.message, stack: err.stack, name: err.name }
|
||||
: { message: String(err), raw: err },
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
reqBody: req.body,
|
||||
reqParams: req.params,
|
||||
reqQuery: req.query,
|
||||
} satisfies ErrorContext;
|
||||
: { message: String(err), raw: err, stack: rootError.stack, name: rootError.name },
|
||||
rootError,
|
||||
);
|
||||
|
||||
res.status(500).json({ error: "Internal server error" });
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ export const httpLogger = pinoHttp({
|
||||
const ctx = (res as any).__errorContext;
|
||||
if (ctx) {
|
||||
return {
|
||||
err: ctx.error,
|
||||
errorContext: ctx.error,
|
||||
reqBody: ctx.reqBody,
|
||||
reqParams: ctx.reqParams,
|
||||
reqQuery: ctx.reqQuery,
|
||||
|
||||
Reference in New Issue
Block a user