zod icon indicating copy to clipboard operation
zod copied to clipboard

Type instantiation is excessively deep and possibly infinite" when using Zod with React Hook Form and @hookform/resolvers

Open ahmettavsan opened this issue 6 months ago • 2 comments

Zod 3.25.20 Typescript 5.7 "turbo": "^2.5.3",

i am receiving Type instantiation is excessively deep and possibly infinite.ts(2589) (alias) zodResolver<any, any, any>(schema: any, schemaOptions?: Partial<ParseParams>, resolverOptions?: { mode?: "async" | "sync"; raw?: false; }): Resolver<any, any, any> (+1 overload) import zodResolver import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage, } from "./form";

import { Input } from "./input"; import { Button } from "./button";

const formSchema = z.object({ name: z.string().min(2, { message: "İsim en az 2 karakter olmalı" }), email: z.string().email({ message: "Geçerli bir e-posta girin" }), }); type FormSchema = { name: string; email: string; };

export default function UserForm() { const form = useForm<FormSchema>({ resolver: zodResolver(formSchema), defaultValues: { name: "", email: "", }, });

const onSubmit = (values: FormSchema) => { console.log("Form gönderildi:", values); };

return ( <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="max-w-md space-y-4" > <FormField control={form.control} name="name" render={({ field }) => ( <FormItem> <FormLabel>İsim</FormLabel> <FormControl> <Input placeholder="Adınızı girin" {...field} /> </FormControl> <FormMessage /> </FormItem> )} />

    <FormField
      control={form.control}
      name="email"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Email</FormLabel>
          <FormControl>
            <Input
              type="email"
              placeholder="E-posta adresinizi girin"
              {...field}
            />
          </FormControl>
          <FormMessage />
        </FormItem>
      )}
    />

    <Button type="submit">Gönder</Button>
  </form>
</Form>

); }

ahmettavsan avatar May 22 '25 09:05 ahmettavsan

Can you create a reproduction repo? There are too many other moving parts (config files, dependency resolution) for me to reproduce with the information provided.

colinhacks avatar May 22 '25 18:05 colinhacks

@ahmettavsan can you please try to install versions 3.25.7 and 3.25.8 and tell me if you start having this with version 3.25.8 ?

dr1ss avatar May 24 '25 09:05 dr1ss

👋🏼 I ran into the same error while working on https://github.com/vercel/ai/pull/6421. I upgraded to [email protected]

I created a minimal test case to reproduce the error

TypeScript playground

import * as z3 from 'zod/v3';
import * as z4 from 'zod/v4/core';
import { z } from 'zod/v4'

export function test<
  RESULT extends SCHEMA extends z4.$ZodType
    ? z4.infer<SCHEMA>
    : SCHEMA extends z3.Schema
      ? z3.infer<SCHEMA>
     // ^ Type instantiation is excessively deep and possibly infinite
        : never,
  SCHEMA extends z3.Schema | z4.$ZodType,
>(
  schema: SCHEMA,
): RESULT {
  return {} as unknown as RESULT;
}

const schema = z.object({ foo: z.string()})
const funk = test(schema)
const testString: string = funk.foo

const yo: z4.infer<typeof schema> = {
  foo: 'yo'
}

Update

slightly simpler test case

import * as z3 from 'zod/v3';
import * as z4 from 'zod/v4/core';

export function test<
  RESULT extends SCHEMA extends z3.Schema
    ? z3.infer<SCHEMA>
   // ^ Type instantiation is excessively deep and possibly infinite
    : never,
  SCHEMA extends z3.Schema | z4.$ZodType,
>(
  schema: SCHEMA,
): RESULT {
  return {} as unknown as RESULT;
}

const schema = z3.z.object({ foo: z3.z.string()})
const funk = test(schema)
const testString: string = funk.foo

If I replace SCHEMA extends z3.Schema | z4.$ZodType with just SCHEMA extends z3.Schema then the error goes away, so it has something to do that with the fact that type can be either a z3 or z4 type

The error also goes away when doing SCHEMA extends z4.$ZodType ? z4.infer<SCHEMA> instead of using the z3 APIs in the example above. So there must be something that z4.infer does that z3.infer doesn't?

full example using z4 APIs
import * as z3 from 'zod/v3';
import * as z4 from 'zod/v4/core';
import { z } from 'zod/v4';

export function test<
  RESULT extends SCHEMA extends z4.$ZodType
    ? z4.infer<SCHEMA>
        : never,
  SCHEMA extends z4.$ZodType | z3.Schema,
>(
  schema: SCHEMA,
): RESULT {
  return {} as unknown as RESULT;
}

const schema = z.object({ foo: z.string()})
const funk = test(schema)
const testString: string = funk.foo

gr2m avatar May 27 '25 18:05 gr2m

@OscarCornish figured out the problem of the "Type instantiation is excessively deep and possibly infinite" error in my test case above. It's not a bug with zod.

I think it's because you are defining RESULT before SCHEMA, even though it depends on schema, which is triggering re-evaluation

Here is the working code for reference: playground link

import * as z3 from 'zod/v3';
import * as z4 from 'zod/v4/core';

type InferSchema<S> =
  S extends z3.Schema ? z3.infer<S> :
  S extends z4.$ZodType ? z4.infer<S> :
  never;

export function test<
  SCHEMA extends z3.Schema | z4.$ZodType,
  RESULT = InferSchema<SCHEMA>
  
>(
  schema: SCHEMA,
): RESULT {
  return {} as unknown as RESULT;
}

const schema = z3.z.object({ foo: z3.z.string()})
const funk = test(schema)
const testString: string = funk.foo

Sorry for the noise, feel free to hide my comments as off topic or resolved.

gr2m avatar May 28 '25 04:05 gr2m

I'm not able to reproduce the original issue with the information provided. Reproductions should be self-contained.

It's very likely this is fixed in recent versions, which contain changes to mitigate "Excessively deep" errors.

Zod 4 support for RHF can be tracked here: https://github.com/react-hook-form/resolvers/pull/776

cc @gr2m Both of your original problem cases now work with [email protected] (and possible earlier versions).

cc @ahmettavsan for future reference use triple backticks to contain code blocks in issues

```ts
// typescript code here
```

colinhacks avatar Jun 04 '25 01:06 colinhacks

cc @gr2m Both of your original problem cases now work with [email protected] (and possible earlier versions).

yes, confirmed! Thanks for all your great work @colinhacks!

gr2m avatar Jun 04 '25 02:06 gr2m