2.4.0rc1 (2026-09-28)
Introduction
OmegaConf 2.4.0rc1 previews the first feature release since 2.3.0 in 2022. It
fixes all open bug reports, delivers a broad set of new features, and refreshes
the roadmap for work beyond this release. Highlights include richer structured
config typing with Literal, container unions, and experimental tuples,
alongside improvements to interpolation, resolvers, merging, and validation.
This release includes compatibility changes. Python 3.10 or newer is required;
native tuples now become immutable TupleConfig values; and some implicit
conversions during assignment now warn. Review the API changes below and report
regressions before the final release.
Features
- Add support for the
|and|=operators onDictConfig.cfg1 | cfg2returns a new merged config (equivalent toOmegaConf.merge(cfg1, cfg2)), andcfg1 |= cfg2merges in place (equivalent tocfg1.merge_with(cfg2)). These operators are not supported onListConfigand will raise aTypeError. (#1006) - OmegaConf.to_yaml() now accepts default_flow_style to control YAML collection flow style. (#1075)
- Added
OmegaConf.can_select()for checking if a select-style key path can produce a value without returning a default or raising. (#1129) - The YAML parser will now use
yaml.CSafeLoaderinstead ofyaml.SafeLoaderwhenever possible to speed up parsing (#1150) - The YAML dumper will now use
yaml.CDumperinstead ofyaml.Dumperwhenever possible to speed up dumping (#1152) - Added support for assigning string-valued enums in structured configs from either the enum member name or the enum value. (#1182)
- When accessing a missing key, OmegaConf now suggests similar key names if any exist (e.g. "Did you mean: 'missing'?"). (#1221)
- Support
typing.Literalannotations in structured configs, including as members of unions. (#1228, #1271) - Key paths in
OmegaConf.update(),OmegaConf.select(),OmegaConf.from_dotlist(), andOmegaConf.from_cli()now support backslash escaping so that keys whose names contain literal dots, brackets, or equals signs can be addressed (e.g.r"a\.b"selects the key"a.b"). (#1230) - Structured configs now support unions of typed containers (e.g.
Union[List[int], Dict[str, int]]).OmegaConf.typed_list([], element_type=str)creates an empty list typed asList[str], selecting that branch ofUnion[List[int], List[str]];OmegaConf.typed_dict()similarly specifies dictionary key and value types. (#1261) - Support structured config types as members of unions, with type-driven branch selection and explicit handling for ambiguous mappings. (#1275)
- Added OmegaConf.structural_equality() for comparing configs by unresolved container structure. (#1326)
- Add the
oc.coerceresolver to explicitly convert values using OmegaConf primitive node types before destination validation. (#1332) - Node interpolations can address keys containing literal dots, brackets, colons, or backslashes. (#1335)
- Support
Anyin Union annotations and transparent PEP 695 type aliases. (#144) - Custom resolvers can now validate runtime arguments and return values against their annotations using explicit
"off","warn", and"error"policies. OmegaConf 2.4 defaults to advisory warnings. (#612)
Bug Fixes
- Fix merging an interpolation into a structured config field failing with InterpolationKeyError or ValidationError; the interpolation is now kept unresolved and resolved lazily against the merged result. (#1020)
- Preserve structured list element types when merging a plain list into a missing structured config list field. (#1058)
- Fixed a crash in
OmegaConf.unsafe_mergewhen merging structured configs containing union types. (#1087) - Fix merging enum names into nested lists in structured configs. (#1095)
- Fixed
OmegaConf.merge()andOmegaConf.unsafe_merge()with nested readonly structured configs. (#1102) - Fix
OmegaConf.missing_keys()raising when an interpolation dereferences a missing value, and add aresolve_custom_resolversflag to opt into custom resolver evaluation. (#1118) - Improved missing-key errors for relative interpolations by showing both the original interpolation key and the resolved lookup path. (#1126)
- Fixed
OmegaConf.selectandoc.selectto return the provided default when a relative key climbs above the config root. (#1127) OmegaConf.create()now supportscollections.OrderedDictas both a top-level input and a nested value. (#1156)- Fixed
OmegaConf.resolve()raisingUnsupportedValueTypewhen a custom resolver returns adictorlist. (#1165) - Fixed validation for union-typed values nested in structured config containers during merges and interpolation resolution. (#1166)
- Fixed structured config support for forward references inside container
annotations on Python 3.10 and older. (#1174) - Preserve container identity when assigning a config node to itself. (#1177)
- Fix duplicate key handling during YAML anchor merge operations (#1194)
- Changed
OmegaConf.create(None)to return literalNoneinstead of aDictConfig(None)wrapper. This is a breaking change for code that relied on getting a config object back fromcreate(None). (#1196) - Fixed a bug where merging a missing structured config into an unresolved interpolation could replace the interpolation with the structured type's default value instead of preserving the interpolation. (#1205)
- Fix
OmegaConf.resolve()raisingRuntimeErroron Python 3.12+ when a custom resolver returns aDictConfig. (#1239) OmegaConf.update()now raises aConfigTypeErrorwith a clear message when navigating through a structuredOptionalnode that isNone, instead of anAssertionError. (#1280)- Fix OmegaConf exceptions retaining caller frame locals through traceback reference cycles. (#1295, #1314)
- Fix
ListConfigiteration leakingUnionNodewrappers forList[Union[...]]; iteration now yields the selected concrete values, matching indexing. (#1310) OmegaConf.update()now follows intermediate node interpolations whose
reference chains end at existing config containers, applying nested updates to
the referenced container while preserving the interpolation. (#1329)- Keep the failing key and object type on interpolation errors raised through
OmegaConf.resolve(), so they match the errors raised by direct node access. (#1330) OmegaConf.resolve()now resolves nested interpolations in resolver-returned containers in one call, including when another field refers to the container before its field is visited. (#1334)- Inherited flags are now updated correctly for containers selected by a union type. (#1340)
- Select matching Literal members before broader scalar members in unions, regardless of annotation order. (#1357)
OmegaConf.merge()andOmegaConf.unsafe_merge()no longer fail with anAttributeErrorwhen merging into a null dictionary root, including optional Structured Config fields. (#1360)- Removed the internal
flagsargument from_ensure_containerand made merge conversion preserveallow_objectsexplicitly. (#580) - Integer interpolation segments and integer-looking string paths used by
OmegaConf.select()andOmegaConf.update()can now resolve integer dictionary keys. Configurations reject ambiguous pairs such as1and"1". (#651) - Report the complete key path when creating a nested Structured Config fails. (#702)
- Fix structured config creation for dataclasses inheriting from
typing.Generic. (#731) ListConfig.insert()now follows Python list semantics for negative and out-of-range indices and leaves the list unchanged when validation fails. (#750)- Align
ListConfignegative index behavior more closely with Python lists by supporting negative list-index interpolations and by fixing negative slicing edge cases such ascfg.xs[:-1]on empty lists. (#755) - Limited YAML alias expansion by default to avoid excessive config growth from crafted YAML input, with an environment override for trusted configurations. (#794)
- Fixed
OmegaConf.masked_copylosing typed leaf node classes at the top level of the copy. (#813) - Fixed OmegaConf.structured() mutating existing OmegaConf nodes passed as structured config field values. (#908)
- Fix handling of
attrsclasses that use a default factory (attrs.Factory). (#945) - Preserve structured child type metadata when merging a missing dict-annotated field over an existing structured config. (#998)
API changes and deprecations
- Support for Python 3.6, 3.7, 3.8 and 3.9 has been dropped. OmegaConf now requires Python 3.10+ (#1109)
OmegaConf.resolve()now raisesInterpolationToMissingValueErrorwhen an interpolation dereferences to a missing (???) value, instead of silently overwriting the node with???. This restores the invariant that working with a resolved config gives the same results as working with the unresolved config. (#1131)- A backslash immediately before a key path delimiter (
\.\[\]\=) now escapes that character rather than being treated as a literal backslash followed by an active delimiter. This affects only the rare case of keys whose names end with a backslash:OmegaConf.select(cfg, r"a\.b")previously navigated to key"a\"then"b"; it now resolves to the single key"a.b". Keys ending in a backslash are not idiomatic in YAML and this change is unlikely to be encountered in practice. (#1230) OmegaConf.to_container(..., resolve=True)now resolves each custom resolver at most once within a single conversion pass, even when multiple interpolations reference the same resolved node. This brings its behavior in line withOmegaConf.resolve()for such cases. (#1243)- Support escaped literal
???values with\???across interpolation, resolvers, and YAML. Plain???returned by a resolver is now missing on access. (#1302) - Typed container and union interpolations now validate and convert against their destination type on lazy access, matching eager resolution. (#1332)
- Make
DictConfigandListConfigunhashable, preventing their use as dictionary keys or set elements. (#1333) - Breaking change: Native tuples now create a public, structurally immutable
TupleConfiginstead of being converted to a mutableListConfig. Code that expects tuple input to support list mutation, checks onlyOmegaConf.is_list(), or expectsOmegaConf.to_container()to return a list for tuple input must be updated. UseOmegaConf.is_tuple()for tuple-specific behavior,OmegaConf.is_sequence()when either sequence type is accepted, or pass a list explicitly when mutation is required. Tuple annotations support fixed positional and homogeneous variadic types, complete replacement merges, typed container unions, native tuple conversion, and tuple-style sequence operations. Tuple semantics are experimental in OmegaConf 2.4 and feedback is welcome. (#392) - Direct assignment and typed-container mutation now warn when they implicitly convert a value to another type. Use
OmegaConf.update()for explicit conversion. Assigning structured-config objects or classes to structured-config fields retains its existing behavior. (#459) - Change
OmegaConf.get_type()to returnNoneTypefor OmegaConf nodes containingNone, and validateNone/NoneTypeannotations. (#928) - Undeprecated
OmegaConf.register_resolver()as the canonical custom resolver API, and deprecatedOmegaConf.register_new_resolver()andOmegaConf.legacy_register_resolver(). (#969)
Improved Documentation
- Update documentation about merging lists examples. (#1176)
- Add docstrings to public OmegaConf methods:
create,structured,load,from_cli,has_resolver,get_cache,set_cache,clear_cache,copy_cache,set_readonly,is_readonly,set_struct,is_struct,is_missing,is_interpolation,is_list,is_dict,is_config,get_type,flag_override,read_write, andopen_dict. (#1222) - Documented
OmegaConf.mergebehavior withMISSINGvalues: a missing value on the source side does not overwrite a non-missing value on the target. (#771)
Miscellaneous changes
antlr4runtime is now vendored to prevent conflicts with other dependencies. (#1091)