Skip to content

ValidationError raised when a field has multiple aliases and one is passed through the constructor and the other is available as an environment variable. #542

@lucacerone

Description

@lucacerone

When a setting class uses multiple aliases for one of the fields, a validation error is raised if I use one alias in the constructor,
but there is an environment variable with the name of the other alias.

This is the version of the packages I have installed:

pydantic==2.6.4
pydantic-settings==2.2.1
pydantic_core==2.16.3

I define a class like:

from pydantic import Field, AliasChoices
from pydantic_settings import BaseSettings, SettingsConfigDict

class Example(BaseSettings):
  model_config = SettingsConfigDict(env_prefix='PREFIX')

  name: str
  last_name: str = Field(validation_alias=AliasChoices("PREFIX_LAST_NAME", "PREFIX_SURNAME"))

If I run:

Example(name="john", PREFIX_LAST_NAME="doe")

the object is validated correctly.

However, if there was an environment PREFIX_SURNAME, then the validation would fail.

For example:

import os
os.environ["PREFIX_SURNAME"] = "smith"

Example(name="john", PREFIX_LAST_NAME="doe")

fails with this error:

ValidationError                           Traceback (most recent call last)
Cell In[26], line 1
----> 1 Example(name="john", PREFIX_LAST_NAME="doe")

File ~/miniforge3/envs/domestika-redshift-dev/lib/python3.12/site-packages/pydantic_settings/main.py:84, in BaseSettings.__init__(__pydantic_self__, _case_sensitive, _env_prefix, _env_file, _env_file_encoding, _env_ignore_empty, _env_nested_delimiter, _env_parse_none_str, _secrets_dir, **values)
     71 def __init__(
     72     __pydantic_self__,
     73     _case_sensitive: bool | None = None,
   (...)
     82 ) -> None:
     83     # Uses something other than `self` the first arg to allow "self" as a settable attribute
---> 84     super().__init__(
     85         **__pydantic_self__._settings_build_values(
     86             values,
     87             _case_sensitive=_case_sensitive,
     88             _env_prefix=_env_prefix,
     89             _env_file=_env_file,
     90             _env_file_encoding=_env_file_encoding,
     91             _env_ignore_empty=_env_ignore_empty,
     92             _env_nested_delimiter=_env_nested_delimiter,
     93             _env_parse_none_str=_env_parse_none_str,
     94             _secrets_dir=_secrets_dir,
     95         )
     96     )

File ~/miniforge3/envs/domestika-redshift-dev/lib/python3.12/site-packages/pydantic/main.py:171, in BaseModel.__init__(self, **data)
    169 # `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks
    170 __tracebackhide__ = True
--> 171 self.__pydantic_validator__.validate_python(data, self_instance=self)

ValidationError: 1 validation error for Example
PREFIX_SURNAME
  Extra inputs are not permitted [type=extra_forbidden, input_value='smith', input_type=str]
    For further information visit https://errors.pydantic.dev/2.6/v/extra_forbidden

however:

import os
os.environ["PREFIX_SURNAME"] = "smith"

Example(name="john", PREFIX_SURNAME="doe")

works as I expected, and uses the value "doe" that I explicitly passed through the constructor.

Maybe I have the wrong expectation, but I thought that if I explicitly constructed the object using one of the two aliases, the value coming from the environment should have been discarded, and not passed as an extra argument to the object causing the validation error.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions