Skip to main content
Version: 2.4 (prerelease)

Validation and conversion

An untyped config stores supported values without a declared field type. A structured config uses its annotations to validate values at runtime. A value already of the declared type can be assigned directly:

>>> from dataclasses import dataclass
>>> from omegaconf import OmegaConf
>>> @dataclass
... class Settings:
... port: int = 80
>>> cfg = OmegaConf.structured(Settings)
>>> cfg.port = 8080
>>> cfg.port
8080

Request conversion explicitly​

Use OmegaConf.update() when the input needs conversion to the destination type. It applies the field's normal validation rules and raises ValidationError if conversion is impossible:

>>> OmegaConf.update(cfg, "port", "9000")
>>> cfg.port
9000

In 2.4, direct assignment and typed list or dict mutation still convert compatible values, but emit FutureWarning. Supply the declared type or use OmegaConf.update() when you intend conversion. Assigning a list to a tuple-typed field, or a tuple to a list-typed field, also warns.

Resolver results and interpolations​

A resolver's return value and the destination field are checked separately. In a typed field, an interpolation result is validated against the field type on lazy access and on OmegaConf.resolve(). A typed container result is validated against the destination's element and key types as well.

oc.coerce asks for a specific primitive type within an interpolation, before destination validation. For example, ${oc.coerce:int,${oc.env:PORT}} converts an environment string to an integer even when the destination has no type annotation. See built-in resolvers.

A typed node interpolation uses the destination annotation when read. It does not change the source value. II("source") is equivalent to SI("${source}"); both let a static type checker accept an interpolation expression as a typed field default.

>>> from dataclasses import dataclass, field
>>> from omegaconf import OmegaConf, SI
>>> @dataclass
... class Ports:
... source: list[str] = field(default_factory=lambda: ["80", "443"])
... numbers: list[int] = SI("${source}")
>>> cfg = OmegaConf.structured(Ports)
>>> list(cfg.numbers)
[80, 443]
>>> list(cfg.source)
['80', '443']
>>> OmegaConf.resolve(cfg)
>>> list(cfg.numbers)
[80, 443]

An incompatible source raises InterpolationValidationError on access or during resolve(). A source container that already matches the destination type may be returned directly; do not rely on a copy being made.

Unions​

Union branch selection avoids implicit conversion because the intended branch would be ambiguous. The value must match a declared branch. Once a structured branch is selected, its own fields follow normal structured config validation and conversion rules. See supported types for typed container and structured unions.