-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[question] is it possible to stop parsing on the first error? #1403
Comments
Zod is designed to surface as many errors as possible, so not really. Some sort of |
hey, @colinhacks, first of all, thank you for the great work 💪🏽! I understand that's not the intended original use case for Zod. I'm moving from Joi -- which I like, but lacks the type inference Zod does so well -- and my idea was to migrate all schemas. My problem is that I've been also using Joi to validate HTTP payloads on a Hapi service and some of those validations can be expensive. Maybe my case is too specific, and it wouldn't worth the changes, but maybe HTTP payload validation could be a new use case that Zod might also address :) Otherwise, and obviously, please, close the issue -- I don't want to bother you with things out of the scope of the project. |
+1 Bailing out on very first error, should be as simple as throwing an exception the moment you stumble on one. No? |
+1 |
There is support for aborting early when using .superRefine. It is more work but might fit your use case. |
hey, @irrelevation thank you for pointing that out, but I think .superRefine avoids the main benefit of using Zod (or other type inference library), which is expressing types in a declarative way. |
I agree that the design is structured to expose as many errors as possible - however, I disagree that it's not a common use case to need to halt mid-validation. A pretty common use-case is form-validation utilizing database queries. Example: if I want to validate a simple email/password form, I can Just my two cents, but it would be a major improvement in an already amazing package. I can see huge value in a simple Thanks again, @colinhacks, for Zod - it's a great resource! |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Definitely still relevant and would be greatly appreciated |
I believe this is a case of dualing use-cases: people fought pretty hard for the current API of "surface as many errors as possible" since we used to fail fast.
I think this very neatly describes why I avoid using the blessed internal validators: they're just too "special case"-y and require to much refactoring if you stray outside of their narrow use-case. If you need to control the parallelism of your validation logic, I would building up some composable Another option is to use const schema = z.object({
foo: z
.string()
.email()
.pipe(
z.string().superRefine(() => {
// super expensive calc
})
),
}); That won't work for all use-cases and now you have to deal with the |
Plus. It would be a significant improvement for zod. |
+1 |
I run a fetch to check if duplicates exists in database for example email or username. ( i have a lot of unique columns in other tables too) currently i am running my fetch separate from zod which is slightly inconvenient for the beautiful generic structure of my app |
In form validation, it's more common to display only one error for a field and not to throw multiple errors at our users. For example:
Also, in this kind of form validation, there's no point in validating if an empty string is an email. When we add a few more "expensive" rules in the validation chain, for example, we ping a server, the issue becomes more apparent. I can understand that |
@gerardolima Y u close 🫤 |
Was this added in zod, or just closed because the original poster no longer needs it anymore? |
Closed?!? |
hey, @TamirCode, @JaneJeon and @carlBgood, I had closed this issue because I believe this use case is not intended to be tackled by Zod (which I think is fair). I reopened because your messages indicate this may be an important subject to you. I opened this ticket some time ago, and I've already solved my problem, so I won't really be an active part of this conversation. Cheers |
I have stumbled into the same issue, I need to bail validation on specific errors (like express-validator allows to https://express-validator.github.io/docs/api/validation-chain/#bail). One approach could be to do chain validations separately (tedious) or maybe just get the first error and do the heavy calculation on another schema. I believe it would be a nice addition to this incredible tool. Cheers |
@colinhacks what would be the problem supporting something such as Furthermore, what would be the downside of it? What about performance improvements? schema.parse(value, { abortEarly: true })
schema.safeParse(value, { abortEarly: true })
await schema.parseAsync(value, { abortEarly: true })
await schema.safeParseAsync(value, { abortEarly: true }) |
It is implemnted in commit: fabian-hiller/valibot@37ac397 interface:
|
+1 guys. In my case, I have a refine that is an asyncronous call (to verify email addresses). Personally I like the I guess that at least having the current validity state in the super refine would also work in my scenario! Workaround in the meantime const validation = z.email().min(2); // Just an example, you could have more
const refinedValidation = validation.refine(async (value) => {
try {
validation.parse(value);
return await validateEmail(value).then(() => !0).catch(() => !1);
}
catch (e) {
// Skipping as already invalid
return !0;
}
}, "error.marketing_cloud_invalid_email"); I think it's awful considering that for multiple refiners is't a lot of code, but this should work. (I'll update if not 😁) |
+1 from my side |
+1 it would be a great option to have, it would avoid duplicate validations. |
We were trying to use zod for general validation (client/server) with superforms but the inability to bail early on the first error prevents this, as valuable server resources are wasted when zod still tries to validate the rest of the data even though the first entry is already faulty. Devs overwhelmingly want to have the option for a early bail mode, I'm really wondering why the maintainers are so set against it. It's just an option, and it's always good to have options, right @colinhacks. |
@MentalGear I've just been finding exactly the same issue as you. Very frustrating. I notice that another library superforms supports is VineJS which does appear to have a "bail" mode https://vinejs.dev/docs/schema_101#bail-mode However that currently throws a "node:dns" warning. Nothing is ever simple! Update: Ah, I see that it's intended only for backend https://vinejs.dev/docs/introduction#can-i-use-vinejs-in-a-front-end-application So if your superforms usage is part of a Sveltekit server.js file, in theory that should work and solve the problem. But not for an SPA +page.svelte. The search continues. |
abortEarly is very handy when you have multi-step forms. Especially, because the superRefine error order is messy so you end up showing errors some steps ahead affecting the using experience. |
Like many here, I'm also queyring my database to check for email addresses in my validation and noticed that it was executing every time, even when the email was not valid. To get around this, I just added a bit of a mix from what the others mentioned. Rather than chaining all the default checks before the superRefine(), I just do within it. Then use the fatal flag when using ctx.addIssue(). const emailSchema = z.string().superRefine(async (email, ctx) => {
const emailTest = z.string().email().safeParse(email)
if (!emailTest.success) {
ctx.addIssue({
code: ZodIssueCode.invalid_string,
validation: 'email',
message: 'Invalid Email',
fatal: true,
})
return z.NEVER
}
// Do email query here
}) |
Here's an even more complex example that I have working with In my example, I'm parsing a large address object that allows for both mailing and physical addresses. I add an additional // define the basic schema
const basicAddressSchema = z.object({
mailing: z.object({
line1: z.string().min(2),
line2: z.string().optional(),
city: z.string().min(2),
subdivision: z.string().min(2),
postalCode: z.string().min(2),
country: z.string().min(2),
}),
physical: z.object({
isSameAsMailing: z.boolean(),
line1: z.string().min(2),
line2: z.string().optional(),
city: z.string().min(2),
subdivision: z.string().min(2),
postalCode: z.string().min(2),
country: z.string().min(2),
}),
})
// set up actual address schmea with the super refine method
const addressSchema = basicAddressSchema.superRefine((address, ctx) => {
// create my uuid schema, you would need to match your actual data
const uuidSchema = z.object({
[uuid]: z.object({
address: basicAddressSchema,
}),
})
// parse the schema
const uuidValidation = uuidSchema.safeParse({ [uuid]: { ...address } })
// if there are basic errosrs
if (!uuidValidation.success) {
// iterate over each
uuidValidation.error.issues.forEach((error) => {
// add them to the ctx
ctx.addIssue({
...error,
})
})
// return to prevent any further cod execution
return z.NEVER
}
console.log("this will not appear if there are errors")
}) |
+1 to this, I have the same use case with this reply. Has this been added or are there no plans in adding this? |
+1 |
Not a common use-case? That is one of the weirdest things I ever read! I would argue the opposite. Why would you WANT to keep validating a field that already failed validation? If a field is set to "required", why would you need to also check if it's a valid e-mail if it's blank? Makes absolutely no sense. Abort early should be the DEFAULT. What exactly would you do with all those validations that fails for an empty string? Show 5 failed validation messages to the user? Crazy. |
+1 |
3 similar comments
+1 |
+1 |
+1 |
@colinhacks Please reconsider this |
Sakht londa he. Kr de bhai implement. |
+1 -- I can't understand why there is so much resistance to adding this feature. It's already supported inside of superRefine, so it's not like there's some kind of philosophical block here, but using superRefine to make this happen isn't a good DX when people actually have pretty straightforward schema definitions and just want to get a single error at a time out of the parse call. |
+1 |
The absence of early abort is basically the only reason I don't use Zod. |
+1 |
It think it should be clear by now that the maintainer won't receive updates on this closed issue any more. |
This ticket looks very much open to me... |
🤔, it still open yet |
I can't agree more, imagine you have a list of expensive validations, but first 2 or 3 are just some format (length, pattern) validations, it would be great to abort the validations there and avoid those expensive ones. |
This is the exact issue I am having right now. I have over 15 forms with their UI already built, trying to do frontend/backend validation and integration only to discover this roadblock. Having to resort to using verbose and less readable |
This is the exact issue I am having right now. I have over 15 forms with their UI already built, trying to do frontend/backend validation and integration only to discover this roadblock and I'd have to resort to using verbose and less readable superRefine even for build-in validation methods. |
Yes. It is extremely strange that this validation library is as popular as it is with this obvious limitation. |
I assume the maintainer has unsubscribed a long time ago from this topic. We need to add a new issue, summarize this topic, and reference it, before a next major version is set/released soon. |
A new issue has been created: #3884. |
I'm using Zod to validate HTTP payloads, some of which may be expensive to validate. Is it possible for
schema.parse()
and their friends to stop on the first error and return a single ZodIssue?The text was updated successfully, but these errors were encountered: