You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI密码验证自定义错误未生效,如何返回指定错误信息?

FastAPI自定义密码长度验证错误不生效的问题解决

问题描述

尝试用FastAPI实现登录认证,要求密码长度小于6时返回自定义错误信息,但实际返回的是Pydantic默认的验证错误。

实现代码

class AuthSchema(BaseModel):
    email: str
    password: constr(min_length=6)

    @validator("password")
    def validate_password(cls, value):
        if len(value) < 6:
            raise HTTPException(status_code=400, detail="Password must be at least 6 characters long")
        return value


@router.post("/login", response_model=CustomResponse)
async def login_user(user: AuthSchema, db: Session = Depends(db.get_session)):
    try:
        if not UserServices().verify_user_password(db, user.email, user.password):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid credentials"
            )
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )
    token = token_services.create_access_token({
        "id": user.id,
        "role": user.role
    })
    return CustomResponse(
        message="User logged in successfully",
        data={
            "token": token
        },
        status=200
    )

实际返回错误

{
  "detail": [
    {
      "type": "string_too_short",
      "loc": [
        "body",
        "password"
      ],
      "msg": "String should have at least 6 characters",
      "input": "123",
      "ctx": {
        "min_length": 6
      },
      "url": "https://errors.pydantic.dev/2.6/v/string_too_short"
    }
  ]
}

问题原因

  1. Pydantic验证优先级问题:你使用的constr(min_length=6)是Pydantic内置的字段约束验证器,它会优先于自定义的@validator执行。当密码长度不足时,内置验证先触发并返回默认错误,自定义的验证逻辑根本不会被执行。
  2. 版本适配问题:Pydantic 2.x中,@validator是兼容旧版本的装饰器,官方推荐使用新的@field_validator,但核心原因还是内置约束的优先级更高。

解决方法

方法一:移除内置约束,使用自定义字段验证器

直接去掉constr(min_length=6),改用Pydantic 2.x推荐的@field_validator实现自定义验证,确保逻辑完全由自己控制:

from pydantic import BaseModel, field_validator
from fastapi import HTTPException

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

    @field_validator("password")
    def validate_password(cls, value):
        if len(value) < 6:
            raise HTTPException(status_code=400, detail="Password must be at least 6 characters long")
        return value

方法二:全局捕获Pydantic验证错误,统一自定义响应

如果需要保留内置约束(比如自动生成接口文档时的长度提示),可以通过FastAPI的异常处理器全局捕获ValidationError,将默认错误转换成自定义消息:

from fastapi import Request, status
from fastapi.responses import JSONResponse
from pydantic import ValidationError

# 在你的FastAPI实例中添加异常处理器
@app.exception_handler(ValidationError)
async def custom_validation_exception_handler(request: Request, exc: ValidationError):
    custom_detail = []
    for err in exc.errors():
        # 针对密码长度不足的错误替换消息
        if err["type"] == "string_too_short" and err["loc"][-1] == "password":
            custom_detail.append({"msg": "Password must be at least 6 characters long"})
        else:
            custom_detail.append({"msg": err["msg"]})
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content={"detail": custom_detail}
    )

方法三:使用Pydantic的自定义错误消息(保留内置约束)

在Pydantic 2.x中,可以通过Annotated结合StringConstraints来设置自定义错误消息,既保留内置验证,又替换默认提示:

from pydantic import BaseModel, StringConstraints
from typing import Annotated

class AuthSchema(BaseModel):
    email: str
    password: Annotated[str, StringConstraints(
        min_length=6,
        min_length_msg="Password must be at least 6 characters long"
    )]

内容的提问来源于stack exchange,提问作者ogz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:05:01