본문으로 건너뛰기

오류 사용자 지정

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());