pythonpython-3.xvalidationpydanticpydantic-v2

Pydantic: How to return user friendly validation error messages?


Is there any way to change the validation messages from pydantic? The problem is this: I want to return these validation messages to my frontend but not all of the users prefer the language english and the validation messages are not user friendly. So my question is: Is there any way to change the pydantic validation messages?

If I continue writing like this, I'll end up creating boilerplate code, which I obviously want to avoid. And I don't see the point of using Pydantic if I'm going to perform all the validations myself just to change the message.

class RegisterModel(BaseModel):
    email: EmailStr
    password: str

    @field_validator("password", mode="before")
    def validate_password(cls, value):
        if not isinstance(value):
            raise ValueError("Password must be a string.")
        if len(value) < 2:
            raise ValueError("Password must have at least 8 characters.")
        if len(value) > 32:
            raise ValueError("Password must not have more than 32 characters.")
        if not re.search(r"[A-Z]", value):
            raise ValueError("Password must contain at least one uppercase letter.")
        if not re.search(r"[0-9]", value):
            raise ValueError("Password must contain at least one digit.")
        
        return value


Solution

  • Option 1: Post-process ValidationError using .errors() — then translate

    Let Pydantic do its job, then map error codes to your localized messages.

    python
    
    from pydantic import BaseModel, EmailStr, ValidationError
    
    class RegisterModel(BaseModel):
        email: EmailStr
        password: str
    
    try:
        RegisterModel(email="invalid", password="ok")
    except ValidationError as e:
        translated = []
        for err in e.errors():
            translated.append({
                "field": err["loc"][0],
                "code": err["type"],  # like "value_error.email"
                "message": translate(err["type"])  # your i18n logic here
            })
        print(translated)
    

    You get the benefit of built-in validators and localized messages.