Capítulo 43 de 61

Chapter 43: Per-Parse Error Customization

Core Idea

An error map can be passed directly into .parse()/.safeParse() for one-off message overrides scoped to a single call, and a reportInput flag opts into including the raw input value in issues (off by default to avoid leaking sensitive data into logs).

Key Concepts

  • Per-parse error map: schema.parse(input, { error: (iss) => "..." }) — lower precedence than any schema-level custom message, so a schema-level error string still wins if one was set.
  • Discriminating issue types: iss.code distinguishes issue kinds ("invalid_type", "too_small", etc.) inside the error map function, each with its own extra fields (iss.expected, iss.minimum, ...).
  • reportInput: true: by default Zod omits the raw input value from issue objects (to avoid accidentally logging sensitive data); passing this flag includes it as issue.input.

Code Examples

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

// per-parse has LOWER precedence than a schema-level message
const withSchemaError = z.string({ error: "highest priority" });
const result = withSchemaError.safeParse(12, { error: () => "lower priority" });
result.error.issues; // [{ message: "highest priority", ... }]

// discriminating on issue code inside a per-parse map
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}`;
  },
});

// including the raw input value
z.string().parse(12, { reportInput: true });
// ZodError: [{ code: "invalid_type", input: 12, path: [], message: "..." }]
  • What it demonstrates: per-parse messages losing to schema-level ones, issue-code discrimination, and opting into input-inclusive issues.

Anti-patterns

  • Enabling reportInput: true on schemas handling sensitive data (passwords, tokens) without redaction: the raw input gets attached to every issue object, which can end up in logs or error-tracking services.

Key Takeaways

  1. Per-parse error maps are for one-off overrides at a specific call site — for anything reusable, put the customization on the schema itself instead.
  2. reportInput is opt-in by design; treat it as a debugging aid, not a default for production schemas over sensitive fields.
  3. The iss.code discriminated union is the same shape whether the error map is schema-level, per-parse, or global — the precedence chain determines which one runs, not the API shape.

Connects To

  • The error Param & Schema-Level Customization: the higher-precedence layer this per-parse map falls back beneath.
  • Global Error Customization, Internationalization & Precedence: the full precedence chain this chapter's mechanism sits within.