Skip to main content
Module

x/zod/ZodError.ts

TypeScript-first schema validation with static type inference
Extremely Popular
Go to Latest
File
import type { TypeOf, ZodType } from "./index.ts";import { Primitive } from "./helpers/typeAliases.ts";import { util, ZodParsedType } from "./helpers/util.ts";
type allKeys<T> = T extends any ? keyof T : never;
export type inferFlattenedErrors< T extends ZodType<any, any, any>, U = string> = typeToFlattenedError<TypeOf<T>, U>;export type typeToFlattenedError<T, U = string> = { formErrors: U[]; fieldErrors: { [P in allKeys<T>]?: U[]; };};
export const ZodIssueCode = util.arrayToEnum([ "invalid_type", "invalid_literal", "custom", "invalid_union", "invalid_union_discriminator", "invalid_enum_value", "unrecognized_keys", "invalid_arguments", "invalid_return_type", "invalid_date", "invalid_string", "too_small", "too_big", "invalid_intersection_types", "not_multiple_of",]);
export type ZodIssueCode = keyof typeof ZodIssueCode;
export type ZodIssueBase = { path: (string | number)[]; message?: string;};
export interface ZodInvalidTypeIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_type; expected: ZodParsedType; received: ZodParsedType;}
export interface ZodInvalidLiteralIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_literal; expected: unknown;}
export interface ZodUnrecognizedKeysIssue extends ZodIssueBase { code: typeof ZodIssueCode.unrecognized_keys; keys: string[];}
export interface ZodInvalidUnionIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_union; unionErrors: ZodError[];}
export interface ZodInvalidUnionDiscriminatorIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_union_discriminator; options: Primitive[];}
export interface ZodInvalidEnumValueIssue extends ZodIssueBase { received: string | number; code: typeof ZodIssueCode.invalid_enum_value; options: (string | number)[];}
export interface ZodInvalidArgumentsIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_arguments; argumentsError: ZodError;}
export interface ZodInvalidReturnTypeIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_return_type; returnTypeError: ZodError;}
export interface ZodInvalidDateIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_date;}
export type StringValidation = "email" | "url" | "uuid" | "regex" | "cuid";
export interface ZodInvalidStringIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_string; validation: StringValidation;}
export interface ZodTooSmallIssue extends ZodIssueBase { code: typeof ZodIssueCode.too_small; minimum: number; inclusive: boolean; type: "array" | "string" | "number" | "set";}
export interface ZodTooBigIssue extends ZodIssueBase { code: typeof ZodIssueCode.too_big; maximum: number; inclusive: boolean; type: "array" | "string" | "number" | "set";}
export interface ZodInvalidIntersectionTypesIssue extends ZodIssueBase { code: typeof ZodIssueCode.invalid_intersection_types;}
export interface ZodNotMultipleOfIssue extends ZodIssueBase { code: typeof ZodIssueCode.not_multiple_of; multipleOf: number;}
export interface ZodCustomIssue extends ZodIssueBase { code: typeof ZodIssueCode.custom; params?: { [k: string]: any };}
export type DenormalizedError = { [k: string]: DenormalizedError | string[] };
export type ZodIssueOptionalMessage = | ZodInvalidTypeIssue | ZodInvalidLiteralIssue | ZodUnrecognizedKeysIssue | ZodInvalidUnionIssue | ZodInvalidUnionDiscriminatorIssue | ZodInvalidEnumValueIssue | ZodInvalidArgumentsIssue | ZodInvalidReturnTypeIssue | ZodInvalidDateIssue | ZodInvalidStringIssue | ZodTooSmallIssue | ZodTooBigIssue | ZodInvalidIntersectionTypesIssue | ZodNotMultipleOfIssue | ZodCustomIssue;
export type ZodIssue = ZodIssueOptionalMessage & { message: string };
export const quotelessJson = (obj: any) => { const json = JSON.stringify(obj, null, 2); return json.replace(/"([^"]+)":/g, "$1:");};
export type ZodFormattedError<T, U = string> = { _errors: U[];} & (T extends [any, ...any[]] ? { [K in keyof T]?: ZodFormattedError<T[K]> } : T extends any[] ? { [k: number]: ZodFormattedError<T[number]> } : T extends object ? { [K in keyof T]?: ZodFormattedError<T[K]> } : unknown);
export type inferFormattedError< T extends ZodType<any, any, any>, U = string> = ZodFormattedError<TypeOf<T>, U>;
export class ZodError<T = any> extends Error { issues: ZodIssue[] = [];
get errors() { return this.issues; }
constructor(issues: ZodIssue[]) { super();
const actualProto = new.target.prototype; if (Object.setPrototypeOf) { // eslint-disable-next-line ban/ban Object.setPrototypeOf(this, actualProto); } else { (this as any).__proto__ = actualProto; } this.name = "ZodError"; this.issues = issues; }
format(): ZodFormattedError<T>; format<U>(mapper: (issue: ZodIssue) => U): ZodFormattedError<T, U>; format(_mapper?: any) { const mapper: (issue: ZodIssue) => any = _mapper || function (issue: ZodIssue) { return issue.message; }; const fieldErrors: ZodFormattedError<T> = { _errors: [] } as any; const processError = (error: ZodError) => { for (const issue of error.issues) { if (issue.code === "invalid_union") { issue.unionErrors.map(processError); } else if (issue.code === "invalid_return_type") { processError(issue.returnTypeError); } else if (issue.code === "invalid_arguments") { processError(issue.argumentsError); } else if (issue.path.length === 0) { (fieldErrors as any)._errors.push(mapper(issue)); } else { let curr: any = fieldErrors; let i = 0; while (i < issue.path.length) { const el = issue.path[i]; const terminal = i === issue.path.length - 1;
if (!terminal) { curr[el] = curr[el] || { _errors: [] }; // if (typeof el === "string") { // curr[el] = curr[el] || { _errors: [] }; // } else if (typeof el === "number") { // const errorArray: any = []; // errorArray._errors = []; // curr[el] = curr[el] || errorArray; // } } else { curr[el] = curr[el] || { _errors: [] }; curr[el]._errors.push(mapper(issue)); }
curr = curr[el]; i++; } } } };
processError(this); return fieldErrors; }
static create = (issues: ZodIssue[]) => { const error = new ZodError(issues); return error; };
toString() { return this.message; } get message() { return JSON.stringify(this.issues, null, 2); }
get isEmpty(): boolean { return this.issues.length === 0; }
addIssue = (sub: ZodIssue) => { this.issues = [...this.issues, sub]; };
addIssues = (subs: ZodIssue[] = []) => { this.issues = [...this.issues, ...subs]; };
flatten(): typeToFlattenedError<T>; flatten<U>(mapper?: (issue: ZodIssue) => U): typeToFlattenedError<T, U>; flatten<U = string>( mapper: (issue: ZodIssue) => U = (issue: ZodIssue) => issue.message as any ): any { const fieldErrors: any = {}; const formErrors: U[] = []; for (const sub of this.issues) { if (sub.path.length > 0) { fieldErrors[sub.path[0]] = fieldErrors[sub.path[0]] || []; fieldErrors[sub.path[0]].push(mapper(sub)); } else { formErrors.push(mapper(sub)); } } return { formErrors, fieldErrors }; }
get formErrors() { return this.flatten(); }}
type stripPath<T extends object> = T extends any ? util.OmitKeys<T, "path"> : never;
export type IssueData = stripPath<ZodIssueOptionalMessage> & { path?: (string | number)[]; fatal?: boolean;};export type MakeErrorData = IssueData;
type ErrorMapCtx = { defaultError: string; data: any;};
export type ZodErrorMap = typeof defaultErrorMap;export const defaultErrorMap = ( issue: ZodIssueOptionalMessage, _ctx: ErrorMapCtx): { message: string } => { let message: string; switch (issue.code) { case ZodIssueCode.invalid_type: if (issue.received === ZodParsedType.undefined) { message = "Required"; } else { message = `Expected ${issue.expected}, received ${issue.received}`; } break; case ZodIssueCode.invalid_literal: message = `Invalid literal value, expected ${JSON.stringify( issue.expected )}`; break; case ZodIssueCode.unrecognized_keys: message = `Unrecognized key(s) in object: ${util.joinValues( issue.keys, ", " )}`; break; case ZodIssueCode.invalid_union: message = `Invalid input`; break; case ZodIssueCode.invalid_union_discriminator: message = `Invalid discriminator value. Expected ${util.joinValues( issue.options )}`; break; case ZodIssueCode.invalid_enum_value: message = `Invalid enum value. Expected ${util.joinValues( issue.options )}, received '${issue.received}'`; break; case ZodIssueCode.invalid_arguments: message = `Invalid function arguments`; break; case ZodIssueCode.invalid_return_type: message = `Invalid function return type`; break; case ZodIssueCode.invalid_date: message = `Invalid date`; break; case ZodIssueCode.invalid_string: if (issue.validation !== "regex") message = `Invalid ${issue.validation}`; else message = "Invalid"; break; case ZodIssueCode.too_small: if (issue.type === "array") message = `Array must contain ${ issue.inclusive ? `at least` : `more than` } ${issue.minimum} element(s)`; else if (issue.type === "string") message = `String must contain ${ issue.inclusive ? `at least` : `over` } ${issue.minimum} character(s)`; else if (issue.type === "number") message = `Number must be greater than ${ issue.inclusive ? `or equal to ` : `` }${issue.minimum}`; else message = "Invalid input"; break; case ZodIssueCode.too_big: if (issue.type === "array") message = `Array must contain ${ issue.inclusive ? `at most` : `less than` } ${issue.maximum} element(s)`; else if (issue.type === "string") message = `String must contain ${ issue.inclusive ? `at most` : `under` } ${issue.maximum} character(s)`; else if (issue.type === "number") message = `Number must be less than ${ issue.inclusive ? `or equal to ` : `` }${issue.maximum}`; else message = "Invalid input"; break; case ZodIssueCode.custom: message = `Invalid input`; break; case ZodIssueCode.invalid_intersection_types: message = `Intersection results could not be merged`; break; case ZodIssueCode.not_multiple_of: message = `Number must be a multiple of ${issue.multipleOf}`; break; default: message = _ctx.defaultError; util.assertNever(issue); } return { message };};
export let overrideErrorMap = defaultErrorMap;
export const setErrorMap = (map: ZodErrorMap) => { overrideErrorMap = map;};