跳轉至

建立 2026-10-11 更新 2026-10-11

ValidationError 錯誤處理

ValidationError 是 Pydantic 驗證失敗時丟出的例外,它會一次收集所有欄位的錯誤,每筆錯誤都有發生位置(loc)、錯誤類型(type)、訊息(msg)與原始輸入(input)。本頁說明如何讀懂錯誤內容、把錯誤轉成 API 回應,以及自訂錯誤訊息。

ValidationError 裡面有什麼?

from pydantic import BaseModel, Field, ValidationError


class Address(BaseModel):
    city: str
    zip_code: str = Field(pattern=r"^\d{3,6}$")


class Customer(BaseModel):
    name: str
    age: int = Field(ge=0)
    address: Address


try:
    Customer.model_validate({"age": -1, "address": {"city": "台北", "zip_code": "ABC"}})
except ValidationError as e:
    print(e.error_count())  # 3
    for err in e.errors():
        print(err["loc"], err["type"], err["msg"])

輸出:

('name',) missing Field required
('age',) greater_than_equal Input should be greater than or equal to 0
('address', 'zip_code') string_pattern_mismatch String should match pattern '^\d{3,6}$'
鍵 意義
loc 錯誤位置的 tuple;巢狀模型會顯示完整路徑,例如 ('address', 'zip_code'),串列會出現索引
type 機器可讀的錯誤代碼,例如 missing、int_parsing、greater_than_equal
msg 人類可讀的英文訊息
input 造成錯誤的原始輸入值
ctx 部分錯誤附帶的上下文,例如 {'ge': 0}

怎麼把錯誤轉成 API 回應?

e.errors() 回傳 Python 物件,e.json() 回傳 JSON 字串。回傳給前端時,通常只保留欄位路徑與訊息,並移除 input 以免洩漏敏感資料:

from pydantic import BaseModel, ValidationError


class Login(BaseModel):
    email: str
    password: str


def validate_login(payload: dict) -> dict:
    try:
        Login.model_validate(payload)
        return {"ok": True}
    except ValidationError as e:
        return {
            "ok": False,
            "errors": [
                {"field": ".".join(str(p) for p in err["loc"]), "message": err["msg"]}
                for err in e.errors(include_input=False, include_url=False)
            ],
        }


print(validate_login({"email": "a@b.c"}))
# {'ok': False, 'errors': [{'field': 'password', 'message': 'Field required'}]}

FastAPI 已內建這個流程,驗證失敗時會自動回傳 HTTP 422 與錯誤清單,見 FastAPI 整合。

可以把錯誤訊息改成中文嗎?

Pydantic 內建訊息是英文。常見做法有兩種:

  1. 自訂驗證器裡直接寫中文:raise ValueError("密碼至少要包含一個數字"),訊息會變成 Value error, 密碼至少要包含一個數字。
  2. 依 type 對照翻譯:錯誤代碼是穩定的,可以建一張對照表,在回傳前替換訊息。
from pydantic import BaseModel, ValidationError

ZH_MESSAGES = {
    "missing": "此欄位為必填",
    "int_parsing": "請輸入整數",
    "string_too_short": "長度不足",
}


class Form(BaseModel):
    age: int
    name: str


try:
    Form.model_validate({"age": "十八"})
except ValidationError as e:
    for err in e.errors():
        print(err["loc"][0], ZH_MESSAGES.get(err["type"], err["msg"]))
# age 請輸入整數
# name 此欄位為必填

需要完全控制錯誤代碼與訊息時,可以在驗證器中丟出 pydantic_core.PydanticCustomError("my_code", "自訂訊息 {x}", {"x": 1})。

除錯時要注意什麼?

  • 一次看全部錯誤:不要只看第一筆,ValidationError 已經把所有問題都列出來了。
  • 看 loc 找位置:深層巢狀資料的錯誤,loc 會精確指出是第幾筆、哪個欄位。
  • 錯誤訊息附的網址:print(e) 會附上 https://errors.pydantic.dev/... 連結,說明該錯誤類型的成因。
  • 不要吞掉例外:except ValidationError: pass 會讓壞資料悄悄消失,至少要記錄 log。

相關資料