question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Incomplete ZodError with recursive types and regexps?

See original GitHub issue

I believe I am seeing unexpected ZodError behavior with recursive types that use regexps. It’s also entirely possible I am misunderstanding as the error handling is fairly complex – but at least I cannot explain how the version with the regexp cannot find the path to the error, and without the regexp can.


const dogSchema = z.object({
  type: z.literal('dog'),
  dogname: z.string()
});
const catSchema = z.object({
  type: z.literal('cat'),
  catname: z.string()
});
const birdSchema = z.object({
  type: z.string().regex(/bird/),        <------ Uses a regexp
  birdname: z.string()
});
const categorySchema = z.object({
  type: z.literal('category'),
  category: z.string(),
  animal: z.lazy(() => animalSchema)
})
const animalSchema = z.union([
  dogSchema,
  catSchema,
  birdSchema,
  categorySchema,
])
const masterSchema = z.object({
  animals: animalSchema,
})

const input = {
  animals: {
    type: 'category',
    category: 'pets',
    animal: {
      type: 'cat',
      // Missing catname.         <------ No catname! Input error.
    }
  }
}

const parseResult = masterSchema.safeParse(input);
if (!parseResult.success) {
  console.info(parseResult.error);
}

On running this, I receive the following. Zod cannot discriminate the unions (which is WAI), but it also seemingly cannot pin down where the error is. Notice no reference to catname below (in the nested context):

ZodError: [
  {
    "code": "invalid_union",
    "unionErrors": [
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "dog",
            "received": "category",
            "path": [
              "animals",
              "type"
            ],
            "message": "Expected dog, received category"
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "dogname"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "cat",
            "received": "category",
            "path": [
              "animals",
              "type"
            ],
            "message": "Expected cat, received category"
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "catname" <--- (not the nested catname)
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "validation": "regex",
            "code": "invalid_string",
            "message": "Invalid",
            "path": [
              "animals",
              "type"
            ]
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "birdname"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "validation": "regex",
            "code": "invalid_string",
            "message": "Invalid",
            "path": [
              "animals",
              "animal",
              "type"
            ]
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "animal",
              "birdname"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      }
    ],
    "path": [
      "animals"
    ],
    "message": "Invalid input"
  }
]

If I change:

type: z.string().regex(/bird/) to type: z.literal('bird') I get:

ZodError: [
  {
    "code": "invalid_union",
    "unionErrors": [
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "dog",
            "received": "cat",
            "path": [
              "animals",
              "animal",
              "type"
            ],
            "message": "Expected dog, received cat"
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "animal",
              "dogname"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "animal",
              "catname" <----------------------------------------------------- THIS IS WHAT I EXPECT
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "bird",
            "received": "cat",
            "path": [
              "animals",
              "animal",
              "type"
            ],
            "message": "Expected bird, received cat"
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "animal",
              "birdname"
            ],
            "message": "Required"
          }
        ],
        "name": "ZodError"
      },
      {
        "issues": [
          {
            "code": "invalid_type",
            "expected": "category",
            "received": "cat",
            "path": [
              "animals",
              "animal",
              "type"
            ],
            "message": "Expected category, received cat"
          },
          {
            "code": "invalid_type",
            "expected": "string",
            "received": "undefined",
            "path": [
              "animals",
              "animal",
              "category"
            ],
            "message": "Required"
          },
          {
            "code": "invalid_union",
            "unionErrors": [
              {
                "issues": [
                  {
                    "code": "invalid_type",
                    "expected": "object",
                    "received": "undefined",
                    "path": [
                      "animals",
                      "animal",
                      "animal"
                    ],
                    "message": "Required"
                  }
                ],
                "name": "ZodError"
              },
              {
                "issues": [
                  {
                    "code": "invalid_type",
                    "expected": "object",
                    "received": "undefined",
                    "path": [
                      "animals",
                      "animal",
                      "animal"
                    ],
                    "message": "Required"
                  }
                ],
                "name": "ZodError"
              },
              {
                "issues": [
                  {
                    "code": "invalid_type",
                    "expected": "object",
                    "received": "undefined",
                    "path": [
                      "animals",
                      "animal",
                      "animal"
                    ],
                    "message": "Required"
                  }
                ],
                "name": "ZodError"
              },
              {
                "issues": [
                  {
                    "code": "invalid_type",
                    "expected": "object",
                    "received": "undefined",
                    "path": [
                      "animals",
                      "animal",
                      "animal"
                    ],
                    "message": "Required"
                  }
                ],
                "name": "ZodError"
              }
            ],
            "path": [
              "animals",
              "animal",
              "animal"
            ],
            "message": "Invalid input"
          }
        ],
        "name": "ZodError"
      }
    ],
    "path": [
      "animals",
      "animal"
    ],
    "message": "Invalid input"
  }
]

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:13 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
dermotduffycommented, Oct 18, 2021

Perfect, the correct error is included as I expected in my original usecase and I am able to surface it as the likely ‘cause’ as a result.

Thanks @colinhacks, both for this fix and for Zod overall (the solution to my search for "Surely – surely – an intuitive tool that does ${zod} must exist … ").

1reaction
colinhackscommented, Oct 23, 2021

Merged in zod@3.11.0

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error when using recursive type in a function - Stack Overflow
I have a recursive type that extracts the indices from a nested object and puts them in a flat, strongly-typed tuple, like so:...
Read more >
Recursive Regex—Tutorial - RexEgg
About Recursive Regular Expressions. Advanced Regex Tutorial with examples and full tracing of the engine matches.
Read more >
bleachbit Scrollbar broken on release 4.4 - Python - GitAnswer
Node & edges connection types are nullable - graphql-relay-js · How to implement Pan ? ... zod Incomplete ZodError with recursive types and...
Read more >
A Recursive Variant Library for C++ : r/cpp - Reddit
Instantiating standard library templates with an incomplete type is an error, NDR unless explicitly exempted. std::variant provides no such ...
Read more >
Parsing regular expressions with recursive descent - Matt Might
At a high level, the structure of the parser is: /* A data type to represent a regular expression. */ abstract class RegEx...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found