Skip to content

issue: Zod resolver ignores errors from refine on discriminated unions #817

@rlaffers

Description

@rlaffers

Version Number

@hookform/resolvers@5.2.2
react-hook-form@7.63.0
zod@4.1.11

Codesandbox/Expo snack

https://codesandbox.io/p/devbox/solitary-butterfly-whjyds?workspaceId=ws_QVkggKcNdip2PnUx9wfT6Q

Steps to reproduce

  1. Go to the Codesandbox example
  2. Enter "1" in the "low" input
  3. Validation error appears: "union refine error". However, there should also be an error for the "high" input - but this error is missing.
  4. A validation error for "high" was produced by the schema but RHF did not get it. See console for more details.

Expected behaviour

When the refine method defined on a member of a discriminated union produces an error, the Zod resolver and RHF should put that error into the RHF formState. However, the error is not in the form state and the form appears valid, even though it is not.

I verified that the zod schema itself validates the form data correctly (schema.safeParse produces a validation failure). However, this error is not picked up by RHF.

The error is eventually propagated to RHF when I press Submit but never on change.

Code sample

import { z } from 'zod'

const A = z
  .object({
    kind: z.literal("A"),
    high: z.number().min(0).max(100),
    low: z.number().min(0).max(100),
  })
  // ❌ this error is not picked up by RHF
  .refine(
    (v) => {
      console.log("refine-A");
      return v.high >= v.low;
    },
    {
      error: "high < low",
      path: ['high'],
    }
  );

const B = z
  .object({
    kind: z.literal("B"),
    low: z.number().min(0),
    high: z.number().min(0),
  })
  // ❌ this error is not picked up by RHF
  .refine(
    (v) => {
      console.log("refine-B");
      return v.high >= v.low;
    },
    {
      error: "high < low",
      path: ['high'],
    }
  );

const schema = z.discriminatedUnion("kind", [A, B]).refine(
  // ✅ this error is picked up by RHF
  (v) => {
    console.log("refine on union");
    return v.high >= v.low;
  },
  {
    error: "union refine error",
    path: ['low'],
  }
);

// ...inside a React component:
  const { formState: { errors } = useForm({
    resolver: zodResolver(schema),
    mode: 'all',
  })

Relevant log output

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions