Capítulo 41 de 61

Chapter 41: The error Param & Schema-Level Customization

Core Idea

Almost every Zod API accepts an error param — a string or a function ("error map") — for customizing the message attached to validation issues, with the function form receiving rich context about the failing issue.

Key Concepts

  • $ZodError: the base error class; every parse failure's .issues array holds structured objects (code, path, expected, and a human-readable message), not just a flat message string.
  • String shorthand: z.string("Bad!") or z.string().min(5, "Too short!") — a positional string sets the message directly.
  • Params object form: { error: "..." } as an alternative to the positional string, useful when other options are also being passed.
  • Error map (function) form: { error: (iss) => ... } runs at parse time; iss exposes code, input, inst (the originating schema/check), schema (the owning schema — stable even when a check raised the issue, useful for reading schema .meta()), path, and check-specific fields (e.g. iss.minimum on a too_small issue from .min()).
  • Returning undefined from an error map: defers to the next error map in the precedence chain instead of overriding — lets you customize only specific issue codes and fall back to defaults for the rest.

Code Examples

z.string("Not a string!");                    // string shorthand
z.string().min(5, { error: "Too short!" });    // params object form

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

// selectively override one issue code, defer to default for the rest
z.int64({
  error: (issue) => {
    if (issue.code === "too_big") return { message: `Value must be <${issue.maximum}` };
    return undefined; // defer to default message
  },
});

// reading schema metadata inside a global error map via iss.schema
z.config({
  customError: (iss) => {
    const meta = iss.schema && z.globalRegistry.get(iss.schema);
    return `${meta?.title ?? "Field"} is invalid.`;
  },
});
z.string().min(5).meta({ title: "Password" }).safeParse("abc");
// => "Password is invalid."
  • What it demonstrates: the three ways to set a custom message, and using iss.schema + metadata to build a generic, field-aware global error map.

Key Takeaways

  1. Prefer the error-map function over a static string whenever the message needs to vary by input value, issue type, or the field's own metadata.
  2. iss.schema (not iss.inst) is the reliable way to reach the schema's own .meta() from inside an error map, since iss.inst can be a check rather than the schema itself.
  3. Returning undefined from an error map is the mechanism for "customize this one case, leave everything else at Zod's default" — it's not a no-op, it's an explicit defer.

Connects To

  • Per-parse & Global Error Customization: the other two levels of the same precedence chain this schema-level error param participates in.
  • Metadata & Registries: .meta() and z.globalRegistry, used here to build field-aware error messages.