colinhacks/zod · error · Error

Can't use "invalid_type_error" or "required_error" in…

Error message

Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.

What it means

Thrown by processCreateParams at packages/zod/src/v3/types.ts:127 when a schema factory is given both a custom errorMap AND either invalid_type_error or required_error in the same params object. These are two mutually exclusive ways to customize messages — errorMap is the general callback form, while invalid_type_error/required_error are shorthand shortcuts — so Zod refuses to guess which one wins. The check happens at schema construction time, before any data is parsed.

Solutions

  1. Pick one mechanism: keep errorMap and remove invalid_type_error/required_error from the params object.
  2. Or drop errorMap and use only invalid_type_error/required_error for the two targeted messages.
  3. If you need both targeted messages and a custom map, fold the special-case logic into your errorMap callback (branch on iss.code === 'invalid_type' and typeof ctx.data === 'undefined').
  4. Audit the params object passed to the factory — including ones spread from a shared config — for leftover shorthand keys.

Example fix

// before
const schema = z.string({
  errorMap: myErrorMap,
  invalid_type_error: 'Expected a string',
  required_error: 'String is required',
});

// after (fold logic into the error map)
const schema = z.string({
  errorMap: (iss, ctx) => {
    if (iss.code === 'invalid_type') return { message: 'Expected a string' };
    if (typeof ctx.data === 'undefined') return { message: 'String is required' };
    return { message: ctx.defaultError };
  },
});
Defensive patterns

Strategy: validation

Validate before calling

import type { RawCreateParams } from 'zod';

function assertCleanParams(params: RawCreateParams): RawCreateParams {
  if (!params) return params;
  const hasShorthand = 'invalid_type_error' in params || 'required_error' in params;
  const hasErrorMap = 'errorMap' in params && params.errorMap !== undefined;
  if (hasShorthand && hasErrorMap) {
    throw new Error('Refusing to pass both errorMap and shorthand messages to Zod; remove one.');
  }
  return params;
}

// usage: z.string(assertCleanParams(config));

Type guard

function hasConflictingErrorParams(p: unknown): p is { errorMap: unknown; invalid_type_error?: unknown; required_error?: unknown } {
  if (!p || typeof p !== 'object') return false;
  const o = p as Record<string, unknown>;
  const hasMap = typeof o.errorMap !== 'undefined';
  const hasShorthand = typeof o.invalid_type_error !== 'undefined' || typeof o.required_error !== 'undefined';
  return hasMap && hasShorthand;
}

Try / catch

null

Prevention

When it happens

Trigger: Calling a schema factory like `z.string({ errorMap: myMap, invalid_type_error: '...' })` or `z.object({...}, { errorMap: myMap, required_error: '...' })` — i.e. passing both errorMap and one of the shorthand message options together in the second-argument params.

Common situations: Adding invalid_type_error/required_error to an existing schema that already uses a global or local errorMap; copy-pasting params from another schema that had an errorMap; migrating from per-field messages to a shared errorMap and leaving the shorthand keys behind; using z.setErrorMap globally and then also passing shorthand params.

Related errors


AI-assisted analysis of colinhacks/zod@2d90846af9 (2026-08-11). Data as JSON: /api/errors/f83bba4bec81e8c0. Report an issue: GitHub.

Appendix: source

Thrown at packages/zod/src/v3/types.ts:127

export type RawCreateParams =
  | {
      errorMap?: ZodErrorMap | undefined;
      invalid_type_error?: string | undefined;
      required_error?: string | undefined;
      message?: string | undefined;
      description?: string | undefined;
    }
  | undefined;
export type ProcessedCreateParams = {
  errorMap?: ZodErrorMap | undefined;
  description?: string | undefined;
};
function processCreateParams(params: RawCreateParams): ProcessedCreateParams {
  if (!params) return {};
  const { errorMap, invalid_type_error, required_error, description } = params;
  if (errorMap && (invalid_type_error || required_error)) {
    throw new Error(`Can't use "invalid_type_error" or "required_error" in conjunction with custom error map.`);
  }
  if (errorMap) return { errorMap: errorMap, description };
  const customMap: ZodErrorMap = (iss, ctx) => {
    const { message } = params;

    if (iss.code === "invalid_enum_value") {
      return { message: message ?? ctx.defaultError };
    }
    if (typeof ctx.data === "undefined") {
      return { message: message ?? required_error ?? ctx.defaultError };
    }
    if (iss.code !== "invalid_type") return { message: ctx.defaultError };
    return { message: message ?? invalid_type_error ?? ctx.defaultError };
  };
  return { errorMap: customMap, description };
}

export type SafeParseSuccess<Output> = {

View on GitHub (pinned to 2d90846af9)