Zod logo

Customizing errors

In Zod, validation errors are surfaced as instances of the z.core.$ZodError class.

The zod package uses a subclass of this called ZodError that implements some additional convenience methods.

Instances of $ZodError contain an .issues property containing a human-readable message and additional structured information about each encountered validation issue.

import * as z from "zod";
 
const result = z.string().safeParse(12); // { success: false, error: ZodError }
result.error.issues;
// [
//   {
//     expected: 'string',
//     code: 'invalid_type',
//     path: [],
//     message: 'Invalid input: expected string, received number'
//   }
// ]

Every issue inside a $ZodError contains a message property with a human-readable error message. This message can be customized in a number of ways.

The error param

Virtually every Zod API accepts an optional parameters object. The error param is used to customize the error messages produced by a particular schema.

z.string({ error: "Bad!"}).parse(12);
 
// throws ZodError {
//   issues: [
//     {
//       expected: 'string',
//       code: 'invalid_type',
//       path: [],
//       message: 'Bad!'   <-- 👀 custom error message 
//     }
//   ]
// }

Nearly all functions and methods support error.

z.string({ error: "Bad!" });
z.string().min(5, { error: "Too short!" });
z.uuid({ error: "Bad UUID!" });
z.iso.date({ error: "Bad date!" });
z.array(z.string(), { error: "Bad array!" });
z.array(z.string()).min(5, { error: "Too few items!" });
z.set(z.string(), { error: "Bad set!" });
z.array(z.string(), { error: "Bad array!" });
z.set(z.string(), { error: "Bad set!" });
z.array(z.string(), { error: "Bad array!" });

The error param optionally accepts a function, also known as an error map. This function will be called at parse time.

z.string({ error: ()=>`[${Date.now()}]: Validation failure.` });

Note — In Zod v3, there were separate params for message (a string) and errorMap (a function). These have been unified in Zod 4 as error.

The error function received a context object you can use to customize the error message based on the input or other validation information.

z.string({
  error: (iss) => iss.input===undefined ? "Field is required." : "Invalid input."
});

For advanced cases, the iss object provides additional information you can use to customize the error.

z.string({
  error: (iss) => {
    iss.code; // the issue code
    iss.input; // the input data
    iss.inst; // the schema/check that originated this issue
    iss.path; // the path of the error
  },
});

Depending on the API you are using, there may be additional properties available. Use TypeScript's autocomplete to explore the available properties.

z.string().min(5, {
  error: (iss) => {
    // ...the same as above
    iss.minimum; // the minimum value
    iss.inclusive; // whether the minimum is inclusive
    return `Password must have ${iss.minimum} characters or more`;
  },
});

Per-parse error customization

To customize errors on a per-parse basis, pass an error map into the parse method:

const schema = z.string()
 
schema.parse(12, {
  error: iss => "per-parse custom error"
};

This has lower precedence than any schema-level custom messages.

const schema = z.string({ error: "highest priority" });
const result = schema.safeParse(12, {
  error: (iss) => "lower priority",
})
 
result.error.issues;
// [{ message: "highest priority", ... }]

The iss object is a discriminated union of all possible issue types. Use the code property to discriminate between them.

For a breakdown of all Zod issue codes, see the @zod/core documentation.

const result = schema.safeParse(12, {
  error: (iss) => {
    if (iss.code === "invalid_type") {
      return `invalid type, expected ${iss.expected}`;
    }
    if (iss.code === "too_small") {
      return `minimum is ${iss.minimum}`;
    }
    // ...
  }
})

Global error customization

To specify a global error map, use z.config() to set Zod's customError configuration setting:

z.config({
  customError: (iss) => {
    return "globally modified error";
  },
});

Global error messages have lower precedence than schema-level or per-parse error messages.

The iss object is a discriminated union of all possible issue types. Use the code property to discriminate between them.

For a breakdown of all Zod issue codes, see the @zod/core documentation.

const result = schema.safeParse(12, {
  error: (iss) => {
    if (iss.code === "invalid_type") {
      return `invalid type, expected ${iss.expected}`;
    }
    if (iss.code === "too_small") {
      return `minimum is ${iss.minimum}`;
    }
    // ...
  }
})

Internationalization

To support internationalization of error message, Zod provides several built-in locales. These are exported from the @zod/core package.

Note — The zod library automatically loads the en locale automatically. The @zod/minipackage does not load any locale; instead all error messages default to Invalid input.

import * as z from "zod";
import en from "@zod/core/locales/en"
 
z.config(en());

For convenience, you can also references these from the z.core namespace exports from zod/@zod/mini.

import * as z from "zod";
 
z.config(z.core.locales.en());

Locales

The following locales are available:

  • en — English

On this page