需捕获ValidationError异常并调用exc.errors()解析:每个错误含loc(字段路径元组)、msg(提示)、type(错误类型),避免直接序列化含敏感信息的ctx/input字段。

pydantic v2 中如何获取验证失败的具体字段和错误信息
直接用 model.model_dump() 或 dict(model) 会抛出 ValidationError,但默认不带上下文。关键是要捕获异常并解析其 errors() 方法返回的结构。
常见错误现象:接口返回 500 而不是 422,或只看到 “validation error” 却不知道哪个字段、什么规则没过。
- 必须用
try/except ValidationError包裹模型实例化过程,不能依赖后续调用 -
exc.errors()返回的是字典列表,每个元素含loc(字段路径)、msg(提示)、type(错误类型,如value_error.missing) -
loc是 tuple,比如("user", "age")表示嵌套字段;根级字段就是("name",)(注意末尾逗号) - 不要直接 jsonify 整个
exc.errors(),部分字段(如input)可能含敏感数据或不可序列化对象
FastAPI 中自动返回结构化 422 错误的原理与自定义限制
FastAPI 默认把 ValidationError 转成符合 OpenAPI 规范的 JSON 响应,字段在 detail 下,但格式固定、不可控。想加额外字段(如错误码、i18n key)就得自己接管。
使用场景:需要统一错误码体系、做前端表单精准高亮、或对接内部监控系统。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 重写
RequestValidationError异常处理器时,exc.body是原始请求体(bytes),exc.errors()才是校验结果 - FastAPI 的
RequestValidationError和 pydantic 的ValidationError不是同一个类,前者包装了后者 - 若手动调用
MyModel.model_validate(request_body),抛出的是纯 pydantic 异常,不会触发 FastAPI 的 422 处理逻辑 - 自定义响应中避免返回
ctx字段(含动态参数),容易泄露内部逻辑或引发序列化错误
嵌套模型 + Union 类型下错误定位为什么经常不准
当字段声明为 Union[TypeA, TypeB] 且两个类型都有同名字段时,pydantic 会尝试逐个匹配,失败信息里的 loc 可能指向第一个类型,而非实际传入的数据结构。
性能影响:每个 Union 分支都会完整执行一次验证,字段越多、嵌套越深,错误堆栈越长、定位越模糊。
- 用
Field(discriminator="type")替代裸Union,可强制先看 discriminator 字段再分发,错误更精准 - 嵌套模型中某字段为
Optional[List[Item]]且传了null,错误类型是type_error.none_not_allowed,但loc可能显示为("items", 0, "name")—— 实际是顶层字段缺失,不是子项问题 - 调试时打印
exc.json(indent=2)比str(exc)更可靠,后者会省略部分上下文
生产环境绕过 ValidationError 堆栈泄露敏感信息的实操方式
默认异常响应里可能包含字段默认值、正则表达式、甚至函数名(比如自定义 @field_validator 的函数名),这些都不该暴露给调用方。
兼容性影响:pydantic v1 的 error_messages 参数在 v2 中已移除,改用 json_schema_extra 或自定义 __pydantic_core_schema__。
- 在异常处理器中过滤
errors()结果,删掉"ctx"、"url"、"input"等键 - 用
model_config = ConfigDict(strict=True)避免隐式类型转换带来的“看似成功实则失真”问题 - 对手机号、身份证等字段,不要在
Field(pattern=...)里写完整正则,改用@field_validator并在异常中统一返回泛化提示(如 “格式不正确”)
最易被忽略的是:即使用了 Field(default_factory=lambda: ...),如果工厂函数抛异常,错误类型会变成 function_type 而非验证错误,errors() 里根本不会出现该字段 —— 这时候得去查日志,而不是看接口响应。

















