본문으로 건너뛰기

오류 사용자 지정

Zod에서 검증 오류는 z.core.$ZodError 클래스의 인스턴스로 나타납니다.

ZodError 클래스는 zod 패키지에서 몇 가지 편의 메서드를 추가로 구현한 하위 클래스입니다.

$ZodError 인스턴스에는 .issues 배열이 있습니다. 각 이슈에는 사람이 읽을 수 있는 message와 이슈에 관한 추가 구조화 메타데이터가 들어 있습니다.

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'
// }
// ]
import * as z from "zod/mini";

const result = z.string().safeParse(12); // { success: false, error: z.core.$ZodError }
result.error.issues;
// [
// {
// expected: 'string',
// code: 'invalid_type',
// path: [],
// message: 'Invalid input'
// }
// ]

모든 이슈에는 사람이 읽을 수 있는 오류 메시지를 담은 message 속성이 있습니다. 오류 메시지는 여러 방법으로 사용자 지정할 수 있습니다.

error 매개변수

거의 모든 Zod API는 선택적 오류 메시지를 받습니다.

z.string("Not a string!");

이 사용자 지정 오류는 이 스키마에서 발생한 모든 검증 이슈의 message 속성으로 표시됩니다.

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

모든 z 함수와 스키마 메서드는 사용자 지정 오류 메시지를 받습니다.

z.string("Bad!");
z.string().min(5, "Too short!");
z.uuid("Bad UUID!");
z.iso.date("Bad date!");
z.array(z.string(), "Not an array!");
z.array(z.string()).min(5, "Too few items!");
z.set(z.string(), "Bad set!");
z.string("Bad!");
z.string().check(z.minLength(5, "Too short!"));
z.uuid("Bad UUID!");
z.iso.date("Bad date!");
z.array(z.string(), "Bad array!");
z.array(z.string()).check(z.minLength(5, "Too few items!"));
z.set(z.string(), "Bad set!");

원한다면 대신 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.string({ error: "Bad!" });
z.string().check(z.minLength(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()).check(z.minLength(5, { error: "Too few items!" }));
z.set(z.string(), { error: "Bad set!" });

error 매개변수에는 선택적으로 함수를 전달할 수 있습니다. Zod 용어로 오류 사용자 지정 함수를 오류 맵이라고 합니다. 검증 오류가 발생하면 오류 맵은 파싱 시점에 실행됩니다.

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

오류 맵은 컨텍스트 객체를 받으며, 이 객체를 사용해 검증 이슈에 따라 오류 메시지를 사용자 지정할 수 있습니다.

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

고급 사례에서는 iss 객체가 오류를 사용자 지정하는 데 사용할 수 있는 추가 정보를 제공합니다.

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

iss.inst와 달리 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."

사용하는 API에 따라 추가 속성을 사용할 수 있습니다. TypeScript의 자동 완성으로 사용 가능한 속성을 살펴보세요.

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`;
},
});

오류 메시지를 사용자 지정하지 않고 기본 메시지를 사용하려면 undefined를 반환하세요. 더 정확히 말하면 Zod는 우선순위 체인의 다음 오류 맵으로 제어권을 넘깁니다. 일부 오류 메시지만 선택적으로 사용자 지정할 때 유용합니다.

z.int64({
error: (issue) => {
// override too_big error message
if (issue.code === "too_big") {
return { message: `Value must be <${issue.maximum}` };
}

// defer to default
return undefined;
},
});

파싱별 오류 사용자 지정

파싱별로 오류를 사용자 지정하려면 파싱 메서드에 오류 맵을 전달하세요.

const schema = z.string();

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

이는 모든 스키마 수준 사용자 지정 메시지보다 우선순위가 낮습니다.

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

result.error.issues;
// [{ message: "highest priority", ... }]

iss 객체는 가능한 모든 이슈 타입으로 이루어진 판별 유니온입니다. code 속성으로 각 타입을 구분하세요.

모든 Zod 이슈 코드에 대한 자세한 설명은 zod/v4/core 문서를 참조하세요.

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}`;
}
// ...
}
});

이슈에 입력 포함하기

기본적으로 Zod는 이슈에 입력 데이터를 포함하지 않습니다. 민감할 수 있는 입력 데이터가 의도치 않게 로그에 기록되는 것을 방지하기 위해서입니다. 각 이슈에 입력 데이터를 포함하려면 reportInput 플래그를 사용하세요.

z.string().parse(12, {
reportInput: true
})

// ZodError: [
// {
// "expected": "string",
// "code": "invalid_type",
// "input": 12, // 👀
// "path": [],
// "message": "Invalid input: expected string, received number"
// }
// ]

전역 오류 사용자 지정

전역 오류 맵을 지정하려면 z.config()를 사용해 Zod의 customError 설정을 구성하세요.

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

전역 오류 메시지는 스키마 수준 또는 파싱별 오류 메시지보다 우선순위가 낮습니다.

iss 객체는 가능한 모든 이슈 타입으로 이루어진 판별 유니온입니다. code 속성으로 각 타입을 구분하세요.

모든 Zod 이슈 코드에 대한 자세한 설명은 zod/v4/core 문서를 참조하세요.

z.config({
customError: (iss) => {
if (iss.code === "invalid_type") {
return `invalid type, expected ${iss.expected}`;
}
if (iss.code === "too_small") {
return `minimum is ${iss.minimum}`;
}
// ...
},
});

국제화

오류 메시지의 국제화를 지원하기 위해 Zod는 여러 내장 로케일을 제공합니다. 로케일은 zod/v4/core 패키지에서 내보냅니다.

참고 — 일반 zod 라이브러리는 en 로케일을 자동으로 불러옵니다. Zod Mini는 기본적으로 어떤 로케일도 불러오지 않으며, 대신 모든 오류 메시지의 기본값이 Invalid input입니다.

import * as z from "zod";
import { en } from "zod/locales"

z.config(en());
import * as z from "zod/mini"
import { en } from "zod/locales";

z.config(en());

로케일을 지연 로드하려면 동적 가져오기를 사용해 보세요.

import * as z from "zod";

async function loadLocale(locale: string) {
const { default: locale } = await import(`zod/v4/locales/${locale}.js`);
z.config(locale());
};

await loadLocale("fr");

편의를 위해 모든 로케일은 z.locales라는 이름으로 "zod"에서 내보내집니다. Rollup과 Webpack은 이를 실제로 사용하는 로케일만 남도록 트리 셰이킹합니다. esbuild는 그렇지 못하므로(evanw/esbuild#1420) import { z } from "zod" 또는 import z from "zod"를 사용하면 모든 로케일을 번들링합니다. 따라서 esbuild에서는 import * as z from "zod"를 권장합니다.

import * as z from "zod";

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

z.config(z.locales.en());

자체 번역 함수를 사용하면 error 매개변수는 스키마를 생성할 때가 아니라 .parse() 실행 중에 호출됩니다. 따라서 한 번 정의한 스키마도 파싱할 때마다 현재 언어를 반영합니다. 렌더링 시점에 번역하려면 이슈 자체를 번역하세요. code가 키이고, 이슈의 다른 속성이 보간 값입니다.

z.string().min(5, { error: (iss) => t("too_short", iss) }); // at parse time
result.error?.issues.map((iss) => t(iss.code, iss)); // at render time

로케일

다음 로케일을 사용할 수 있습니다.

  • ar — 아랍어
  • az — 아제르바이잔어
  • be — 벨라루스어
  • bg — 불가리아어
  • bn — 벵골어
  • ca — 카탈루냐어
  • ckb — 중앙 쿠르드어
  • cs — 체코어
  • da — 덴마크어
  • de — 독일어
  • el — 그리스어
  • en — 영어
  • eo — 에스페란토어
  • es — 스페인어
  • fa — 페르시아어
  • fi — 핀란드어
  • fr — 프랑스어
  • frCA — 캐나다 프랑스어
  • gu — 구자라트어
  • he — 히브리어
  • hi — 힌디어
  • hr — 크로아티아어
  • hu — 헝가리어
  • hy — 아르메니아어
  • id — 인도네시아어
  • is — 아이슬란드어
  • it — 이탈리아어
  • ja — 일본어
  • ka — 조지아어
  • km — 크메르어
  • kn — 칸나다어
  • ko — 한국어
  • lt — 리투아니아어
  • mk — 마케도니아어
  • ms — 말레이어
  • ne — 네팔어
  • nl — 네덜란드어
  • nn — 뉘노르스크 노르웨이어
  • no — 노르웨이어
  • ota — 오스만 튀르크어
  • ps — 파슈토어
  • pl — 폴란드어
  • pt — 포르투갈어
  • ptBR — 브라질 포르투갈어
  • ro — 루마니아어
  • ru — 러시아어
  • sk — 슬로바키아어
  • sl — 슬로베니아어
  • sv — 스웨덴어
  • ta — 타밀어
  • th — 태국어
  • tk — 투르크멘어
  • tr — 튀르키예어
  • uk — 우크라이나어
  • ur — 우르두어
  • uz — 우즈베크어
  • vi — 베트남어
  • zhCN — 중국어 간체
  • zhTW — 중국어 번체
  • yo — 요루바어

오류 우선순위

다음은 오류 우선순위를 판단하기 위한 빠른 참고 자료입니다. 여러 오류 사용자 지정이 정의되어 있다면 어느 것이 우선할까요? 가장 높은 우선순위부터 가장 낮은 우선순위 순서는 다음과 같습니다.

  1. 검사 수준 오류 — 실패한 개별 검사에 정의된 오류입니다.
z.string().min(5, "Too short!");
  1. 스키마 수준 오류 — 스키마 정의에 직접 지정한 모든 오류 메시지입니다. 스키마 자체의 검사에서 발생한 이슈를 포괄하므로 검사에 별도 오류가 정의되어 있지 않을 때 사용됩니다.
z.string("Invalid name").safeParse(12);          // => "Invalid name"
z.string("Invalid name").min(5).safeParse("ab"); // => "Invalid name"
  1. 파싱별 오류.parse() 메서드에 전달한 사용자 지정 오류 맵입니다.
z.string().parse(12, {
error: (iss) => "My custom error"
});
  1. 전역 오류 맵z.config()에 전달한 사용자 지정 오류 맵입니다.
z.config({
customError: (iss) => "My custom error"
});
  1. 로케일 오류 맵z.config()에 전달한 사용자 지정 오류 맵입니다.
z.config(z.locales.en());