Skip to content
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

Order of z.object props with preprocess gives wrong parse results #3123

Open
lucasbozzo opened this issue Jan 10, 2024 · 4 comments
Open

Order of z.object props with preprocess gives wrong parse results #3123

lucasbozzo opened this issue Jan 10, 2024 · 4 comments
Labels
bug-confirmed Bug report that is confirmed

Comments

@lucasbozzo
Copy link

Version: 3.22.4

It seems that Zod is unable of properly validating props with preprocess if they are not placed at the beginning of the Zod Object.

The following schema should always return an error for second.

const schemaWrong = z.object({
  first: z.string(),
  second: z.preprocess(() => undefined, z.string()),
});

schemaWrong.safeParse({}) // Shows only 1 error in `first`

If we switch the order of the props, then it works:

const schemaFixed = z.object({
  second: z.preprocess(() => undefined, z.string()),
  first: z.string(),
});

schemaWrong.safeParse({}) // Correctly shows 2 errors.

Playground: https://stackblitz.com/edit/typescript-wqj5ep?file=schemas%2FschemaWithDefaultType.ts

Note: Version 3.21 works correctly

@selimb
Copy link

selimb commented Jan 10, 2024

Was just investigating this as well. I believe the behavior changed with #2426, specifically this bit (all comments are mine):

      // This runs preprocess
      const processed = effect.transform(ctx.data, checkCtx);
      // Early return if there are any issues on `ctx`
      if (ctx.common.issues.length) {
        return {
          status: "dirty",
          value: ctx.data,
        };
      }

      if (ctx.common.async) {
        return Promise.resolve(processed).then((processed) => {
          return this._def.schema._parseAsync({
            data: processed,
            path: ctx.path,
            parent: ctx,
          });
        });
      } else {
        // This runs the "inner" schema
        return this._def.schema._parseSync({
          data: processed,
          path: ctx.path,
          parent: ctx,
        });
      }
    }

@JacobWeisenburger
Copy link
Contributor

Perhaps this will help:

const schemaFixed = z.object( {
    first: z.string(),
    second: z.any().transform( () => undefined ).pipe( z.string() ),
} )

// works as expected
const result = schemaFixed.safeParse( {} )
!result.success && console.log( result.error.issues )
// [
//     {
//         code: "invalid_type",
//         expected: "string",
//         received: "undefined",
//         path: [ "first" ],
//         message: "Required",
//     }, {
//         code: "invalid_type",
//         expected: "string",
//         received: "undefined",
//         path: [ "second" ],
//         message: "Required",
//     }
// ]
const schemaFixed = z.object( {
    second: z.any().transform( () => undefined ).pipe( z.string() ),
    first: z.string(),
} )

// works as expected
const result = schemaFixed.safeParse( {} )
!result.success && console.log( result.error.issues )
// [
//     {
//         code: "invalid_type",
//         expected: "string",
//         received: "undefined",
//         path: [ "second" ],
//         message: "Required",
//     }, {
//         code: "invalid_type",
//         expected: "string",
//         received: "undefined",
//         path: [ "first" ],
//         message: "Required",
//     }
// ]

If you found my answer satisfactory, please consider supporting me. Even a small amount is greatly appreciated. Thanks friend! 🙏
https://github.com/sponsors/JacobWeisenburger

@selimb
Copy link

selimb commented Jan 10, 2024

z.any().transform().pipe() can indeed be used to replace z.preprocess! But isn't this still a regression (which has an easy fix, see #3124).

@aaronadamsCA
Copy link

This issue appears to be a duplicate of #2687.

Here is a one-line fix you can apply as a local patch to the Zod package:

I would suggest lending your 👍 to #2912 to encourage a fix to be merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug-confirmed Bug report that is confirmed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants