2025, Oct 20 21:00

Fixing YAML loading in pydantic-settings: use YamlConfigSettingsSource with yaml_file and yaml_config_section

Avoid ValidationError when loading YAML in pydantic-settings. Learn to enable YamlConfigSettingsSource via settings_customise_sources and use yaml_file.

Reading configuration from YAML with pydantic-settings can look deceptively straightforward thanks to yaml_file and yaml_config_section in model_config. Yet simply setting those options does not make BaseSettings load YAML, which often surfaces as a ValidationError about missing fields. Below is a concise walkthrough of why that happens and how to wire YAML properly using the documented customization hook.

Reproducing the issue

The intention is to load a single integer from a YAML section into a settings model. The code is set up with yaml_file and yaml_config_section, and a field that must be populated from YAML.

from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict

class AppConfig(BaseSettings):
    model_config = SettingsConfigDict(
        yaml_file=Path('cfg.yaml'),
        yaml_config_section='section',
    )

    svc_port: int

cfg = AppConfig()

And the YAML file stored alongside the code:

section:
  svc_port: 123

The run fails with a missing field error. In the original case it looked like this:

pydantic_core._pydantic_core.ValidationError: 1 validation error for Settings
port
  Field required [type=missing, input_value={}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/missing

Which clearly indicates that YAML was not read at all.

What is really going on

yaml_file and yaml_config_section exist, but they do nothing by themselves. Due to some restrictions Pydantic has in direct reading of YAML files, you need to customize the settings sources and explicitly add YamlConfigSettingsSource, as described in the documentation. Only then do the YAML-related options make sense. Without that override, BaseSettings will not attempt to read YAML, and your fields will be treated as missing.

Working solution with a section model

One practical approach is to model the YAML section as a nested BaseModel and plug in YamlConfigSettingsSource via the customization hook.

from pydantic import BaseModel
from pydantic_settings import BaseSettings, YamlConfigSettingsSource

class SectionConfig(BaseModel):
    svc_port: int

class AppConfig(BaseSettings):
    section: SectionConfig

    @classmethod
    def settings_customise_sources(cls, settings_cls, **kwargs):
        return (YamlConfigSettingsSource(settings_cls, "cfg.yaml"),)

conf = AppConfig()
print(conf.section.svc_port)

Given this YAML:

section:
  svc_port: 123

The output is the expected 123.

Alternative: use model_config to pass YAML options

It is also possible to keep yaml_file and yaml_config_section in model_config and omit the filename when constructing YamlConfigSettingsSource. In that case, the source picks up parameters from model_config automatically.

from pydantic_settings import BaseSettings, YamlConfigSettingsSource, SettingsConfigDict

class RootOptions(BaseSettings):
    svc_port: int

    model_config = SettingsConfigDict(
        yaml_file='cfg.yaml',
        yaml_config_section='section',
    )

    @classmethod
    def settings_customise_sources(cls, settings_cls, **kwargs):
        return (YamlConfigSettingsSource(settings_cls),)

opts = RootOptions()
print(opts.svc_port)

With the same YAML structure:

section:
  svc_port: 123

This also prints 123.

A note on “extra” fields

It is not necessary to enable extra="allow" just to read values from a YAML section. If a key appears as “extra”, it usually means there is no matching declared field in your model. Once the field is declared, the value maps correctly. This is not related to using sectioned parameters.

Why this matters

Relying solely on yaml_file and yaml_config_section leads to confusing failures because YAML is never consulted. The fix is to explicitly wire YamlConfigSettingsSource via settings_customise_sources, as the documentation suggests. Understanding this small but crucial step saves time and helps keep configuration loading predictable.

Takeaways

If you want to load YAML with pydantic-settings, declare your fields, and then enable YAML as a settings source. You can either pass the filename directly to YamlConfigSettingsSource or keep all YAML-related parameters in model_config and let the source read them from there. If you structure your YAML into sections, you can model that section as a nested BaseModel or read the section directly into fields, depending on your preference. The key is that YAML will only be read after you customize sources accordingly.

The article is based on a question from StackOverflow by rzlvmp and an answer by strawdog.