zod
zod copied to clipboard
wrap internal errors from `preprocess` and `refine`
As explained here zod intentionally does not catch errors from within preprocess and refine.
This is behaving as intended currently. An error in a refinement is considered an application-level bug, not a validation error. The thinking is that catching this error in Zod would make it harder to debug actual real-life bugs, and you can always use try/catch. But if Zod catches these errors, there's no way to opt-out of this and allow errors to bubble up.
However, consider this schema:
z.object({ a: z.array(z.object({ b: z.preprocess(data => { throw new Error('asdf') }, z.date()) }))}).parse({a: [{}]})
The error will be:
Uncaught Error: asdf
at Object.transform (REPL12:1:66)
at ZodEffects._parse (/node_modules/zod/lib/types.js:2137:38)
at ZodObject._parse (/node_modules/zod/lib/types.js:1070:37)
at ZodObject._parseSync (/node_modules/zod/lib/types.js:109:29)
This makes it difficult to know where the error came from. Consider an object schema with many properties (that may also be nested) - if I get this error I don't know which property caused it.
In contrast, the regular zod parsing errors are amazing:
z.object({ a: z.array(z.object({ b: z.date()})) }).parse({a: [{}]})
Error:
[
{
"code": "invalid_type",
"expected": "date",
"received": "undefined",
"path": [
"a",
0,
"b"
],
"message": "Required"
}
]
It tells me exactly the path to the problem in my object.
Proposed solution
I propose that zod will catch my internal error and wrap it in a zod error (and re-throw it) that will at least tell me where the error occurred in the object.
For example something like:
z.object({ a: z.array(z.object({ b: z.preprocess(data => { throw new Error('asdf') }, z.date()) }))}).parse({a: [{}]})
Expected error:
[
{
"code": "preprocess_error",
"path": [
"a",
0,
"b"
],
"message": "Uncaught Error: asdf",
"originalError": <the original error object>
}
]
But allow the behaviour of the "rethrow" to be customizable. I.e. personally I wouldn't want to use the ZodError class at all, and to use my own errors.
I would like to suggest a above PR (https://github.com/colinhacks/zod/pull/3314) as a possible solution for this issue. We could create a similar implementation for refinement as well.