react-hook-form / resolvers

đź“‹ Validation resolvers: Yup, Zod, Superstruct, Joi, Vest, Class Validator, io-ts, Nope, computed-types, typanion, Ajv, TypeBox, ArkType, Valibot, effect-ts and VineJS
https://react-hook-form.com/
MIT License
1.71k stars 155 forks source link

FieldArray errors are overwritten depending on the order of reported errors #605

Closed Kirdock closed 1 year ago

Kirdock commented 1 year ago

Describe the bug Depending on the order, how errors come into the toNestError function, there is a different result. Zod for example sets custom errors (via refine or superRefine), after the errors of it's child (in it's error array). e.g., you have the following errors that come to the toNestError function (after the zod errors were parsed)

{
  people.1.name: Object
  people.0.name: Object
  people: Object
}

then people overwrites the people.1.name and people.0.name error. If the result looks like this

{
  people: Object
  people.1.name: Object
  people.0.name: Object
}

it's working as expected.

To Reproduce Steps to reproduce the behavior:

  1. Go to https://codesandbox.io/s/zod-resolver-manual-implementation-fwtnyf
  2. Click on Submit
  3. Realize that the errors for the two inputs are not shown (overwritten)

Note: I copy&pasted the zod resolver implementation, so that I can add some logs

Codesandbox link (Required) https://codesandbox.io/s/zod-resolver-manual-implementation-fwtnyf

Expected behavior The errors are always set and not overwritten. The order of the reported errors should not matter.

Screenshots image

Additional context Discord discussion

jorisre commented 1 year ago

I'm uncertain if this is a feature we provide. You seem to be attempting to obtain errors at nested levels as well as errors at the root level of an array.

It's either (nested errors, array of errors)

{ "people": [
  { "name": { "message": "String must contain at least 1 character(s)", "type": "too_small", "ref": {} } }, 
  { "name": { "message": "String must contain at least 1 character(s)", "type": "too_small", "ref": {} } }
] } 

or errors at the root level of an array (object of error), but not both.

{"people":{"message":"Duplicates!","type":"custom"}}

We can't mix them because array vs object

@bluebill1049 can you confirm?

Kirdock commented 1 year ago

@jorisre that's not how the react-hook-form works. Array errors and field errors are shown. Array vs object works because it's saved differently.

react-hook-form/resolvers:

{
  "people": {
    "0": {
      "name": {
        "message": "String must contain at least 1 character(s)",
        "type": "too_small"
      }
    }
    "message": "Duplicate",
    "type": "custom"
  }
}

The real react-hook-form implementation would be

{
  "people": {
    "0": {
      "name": {
        "message": "String must contain at least 1 character(s)",
        "type": "too_small"
      }
    },
    "root": {
      "message": "Duplicate",
      "type": "custom"
    }
  }
}

As I said, it is working if I change the order of reported errors, so that the root is first and does not override the other ones

jorisre commented 1 year ago

You're right!

Opened a PR to add this missing feature, feel free to review: https://github.com/react-hook-form/resolvers/pull/621

jorisre commented 1 year ago

Released in 3.30