Skip to content

Commit 66259cc

Browse files
committed
Merge remote-tracking branch 'origin/ph/txWorkerRedis' into ph/txWorkerRedis
2 parents e90c320 + ccab246 commit 66259cc

File tree

1 file changed

+113
-56
lines changed

1 file changed

+113
-56
lines changed

src/server/middleware/error.ts

Lines changed: 113 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { FastifyInstance } from "fastify";
22
import { ReasonPhrases, StatusCodes } from "http-status-codes";
3+
import { ZodError } from "zod";
34
import { env } from "../../utils/env";
45
import { logger } from "../../utils/logger";
56

@@ -20,6 +21,46 @@ export const createCustomError = (
2021
code,
2122
});
2223

24+
const ETHERS_ERROR_CODES = [
25+
"UNKNOWN_ERROR",
26+
"NOT_IMPLEMENTED",
27+
"UNSUPPORTED_OPERATION",
28+
"NETWORK_ERROR",
29+
"SERVER_ERROR",
30+
"TIMEOUT",
31+
"BAD_DATA",
32+
"CANCELLED",
33+
"BUFFER_OVERRUN",
34+
"NUMERIC_FAULT",
35+
"INVALID_ARGUMENT",
36+
"MISSING_ARGUMENT",
37+
"UNEXPECTED_ARGUMENT",
38+
"VALUE_MISMATCH",
39+
"CALL_EXCEPTION",
40+
"INSUFFICIENT_FUNDS",
41+
"NONCE_EXPIRED",
42+
"REPLACEMENT_UNDERPRICED",
43+
"TRANSACTION_REPLACED",
44+
"UNCONFIGURED_NAME",
45+
"OFFCHAIN_FAULT",
46+
"ACTION_REJECTED",
47+
];
48+
49+
const isZodError = (err: unknown): boolean => {
50+
return Boolean(
51+
err && (err instanceof ZodError || (err as ZodError).name === "ZodError"),
52+
);
53+
};
54+
55+
const isEthersError = (error: any): boolean => {
56+
return (
57+
error &&
58+
typeof error === "object" &&
59+
"code" in error &&
60+
ETHERS_ERROR_CODES.includes(error.code)
61+
);
62+
};
63+
2364
export const createCustomDateTimestampError = (key: string): CustomError => {
2465
return createCustomError(
2566
`Invalid ${key} Value. Needs to new Date() / new Date().toISOstring() / new Date().getTime() / Unix Epoch`,
@@ -32,68 +73,84 @@ const flipObject = (data: any) =>
3273
Object.fromEntries(Object.entries(data).map(([key, value]) => [value, key]));
3374

3475
export const withErrorHandler = async (server: FastifyInstance) => {
35-
server.setErrorHandler((error: Error | CustomError, request, reply) => {
36-
logger({
37-
service: "server",
38-
level: "error",
39-
message: `Encountered server error`,
40-
error,
41-
});
42-
43-
// v4 : Contract Prepare Error Handler
44-
if (error.message.includes("code=INVALID_ARGUMENT")) {
45-
return reply.status(StatusCodes.BAD_REQUEST).send({
46-
error: {
47-
code: "BAD_REQUEST",
48-
message: "INVALID_ARGUMENT",
49-
reason: error.message,
50-
statusCode: 400,
51-
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
52-
},
76+
server.setErrorHandler(
77+
(error: Error | CustomError | ZodError, request, reply) => {
78+
logger({
79+
service: "server",
80+
level: "error",
81+
message: `Encountered server error`,
82+
error,
5383
});
54-
}
5584

56-
// v4: Zod Typings Errors
57-
if (error.message.toLowerCase().includes("invalid input")) {
58-
return reply.status(StatusCodes.BAD_REQUEST).send({
59-
error: {
60-
code: "BAD_REQUEST",
61-
message: "Invalid input",
62-
reason: JSON.parse(error.message),
63-
statusCode: 400,
64-
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
65-
},
66-
});
67-
}
85+
// Ethers Error Codes
86+
if (isEthersError(error)) {
87+
return reply.status(StatusCodes.BAD_REQUEST).send({
88+
error: {
89+
code: "BAD_REQUEST",
90+
message: (error as any).code,
91+
reason: error.message,
92+
statusCode: 400,
93+
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
94+
},
95+
});
96+
}
97+
98+
// Zod Typings Errors
99+
if (isZodError(error)) {
100+
const _error = error as ZodError;
101+
let parsedMessage: any[] = [];
68102

69-
// Handle Custom Errors
70-
if ("statusCode" in error && "code" in error) {
71-
// Transform unexpected errors into a standard payload
72-
const statusCode = error.statusCode ?? StatusCodes.INTERNAL_SERVER_ERROR;
73-
const code =
74-
error.code ??
75-
flipObject(StatusCodes)[statusCode] ??
76-
StatusCodes.INTERNAL_SERVER_ERROR;
103+
try {
104+
parsedMessage = JSON.parse(_error.message);
105+
} catch (e) {
106+
console.error("Failed to parse error message:", e);
107+
}
108+
const errorObject =
109+
Array.isArray(parsedMessage) && parsedMessage.length > 0
110+
? parsedMessage[0]
111+
: {};
77112

78-
const message = error.message ?? ReasonPhrases.INTERNAL_SERVER_ERROR;
79-
return reply.status(statusCode).send({
113+
return reply.status(StatusCodes.BAD_REQUEST).send({
114+
error: {
115+
code: "BAD_REQUEST",
116+
message: errorObject.message ?? "Invalid Request",
117+
reason: errorObject ?? undefined,
118+
statusCode: 400,
119+
stack: env.NODE_ENV !== "production" ? _error.stack : undefined,
120+
},
121+
});
122+
}
123+
124+
// Handle Custom Errors
125+
if ("statusCode" in error && "code" in error) {
126+
// Transform unexpected errors into a standard payload
127+
const statusCode =
128+
error.statusCode ?? StatusCodes.INTERNAL_SERVER_ERROR;
129+
const code =
130+
error.code ??
131+
flipObject(StatusCodes)[statusCode] ??
132+
StatusCodes.INTERNAL_SERVER_ERROR;
133+
134+
const message = error.message ?? ReasonPhrases.INTERNAL_SERVER_ERROR;
135+
return reply.status(statusCode).send({
136+
error: {
137+
code,
138+
message,
139+
statusCode,
140+
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
141+
},
142+
});
143+
}
144+
145+
// Handle non-custom errors
146+
return reply.status(StatusCodes.INTERNAL_SERVER_ERROR).send({
80147
error: {
81-
code,
82-
message,
83-
statusCode,
148+
statusCode: 500,
149+
code: "INTERNAL_SERVER_ERROR",
150+
message: error.message || ReasonPhrases.INTERNAL_SERVER_ERROR,
84151
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
85152
},
86153
});
87-
}
88-
89-
// Handle non-custom errors
90-
return reply.status(StatusCodes.INTERNAL_SERVER_ERROR).send({
91-
error: {
92-
statusCode: 500,
93-
code: "INTERNAL_SERVER_ERROR",
94-
message: error.message || ReasonPhrases.INTERNAL_SERVER_ERROR,
95-
stack: env.NODE_ENV !== "production" ? error.stack : undefined,
96-
},
97-
});
98-
});
154+
},
155+
);
99156
};

0 commit comments

Comments
 (0)