Skip to content

RuntimeError: dictionary changed size during iteration in OmegaConf.resolve() on Python 3.12+ #1239

@Moep90

Description

@Moep90

Bug Report

Description

OmegaConf.resolve() raises RuntimeError: dictionary changed size during iteration on Python 3.12+ when a custom resolver returns a DictConfig (Container).

Root Cause

_resolve() in omegaconf/_impl.py iterates over a live dict_keys view:

for k in cfg.keys():
    _resolve_container_value(cfg, k)

Inside _resolve_container_value, when a resolver returns a Container and the current node is a ValueNode, the result is assigned back:

if isinstance(resolved, Container) and isinstance(node, ValueNode):
    cfg[key] = resolved

This assignment modifies the underlying dict while the cfg.keys() view is being iterated. Python 3.12+ introduced stricter checks that raise RuntimeError on structural dict modifications during iteration.

Minimal Reproduction

from omegaconf import OmegaConf, ListMergeMode

def merge(*args):
    return OmegaConf.merge(*args, list_merge_mode=ListMergeMode.EXTEND)

OmegaConf.register_new_resolver("merge", merge, replace=True)

cfg = OmegaConf.create({
    "base": {"x": 1, "y": 2},
    "extra": {"z": 3},
    "merged": "${merge:${base},${extra}}",
})

OmegaConf.resolve(cfg)  # RuntimeError: dictionary changed size during iteration

Traceback

  File ".../omegaconf/_impl.py", line 52, in _resolve
    for k in cfg.keys():
             ~~~~~~~~^^
RuntimeError: dictionary changed size during iteration

Environment

  • Python 3.12+ (confirmed on 3.12 and 3.14)
  • omegaconf 2.4.0.dev4
  • Works on Python ≤ 3.11

Fix

Snapshot the keys before iterating:

for k in list(cfg.keys()):
    _resolve_container_value(cfg, k)

A PR with this fix and a regression test is attached.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions