facebookresearch/detectron2 · error · KeyError

Trying to update key {key}, but {prefix} is not a config, bu

Error message

Trying to update key {key}, but {prefix} is not a config, but has type {type(v)}.

What it means

apply_overrides/safe_update walks each dotted key's parent prefixes and requires every intermediate node to be an OmegaConf config (struct-like node). If an intermediate prefix selects a plain value (int, str, list), the key cannot be descended into and a KeyError is raised.

Source

Thrown at detectron2/config/lazy.py:340

        Args:
            cfg: an omegaconf config object
            overrides: list of strings in the format of "a=b" to override configs.
                See https://hydra.cc/docs/next/advanced/override_grammar/basic/
                for syntax.

        Returns:
            the cfg object
        """

        def safe_update(cfg, key, value):
            parts = key.split(".")
            for idx in range(1, len(parts)):
                prefix = ".".join(parts[:idx])
                v = OmegaConf.select(cfg, prefix, default=None)
                if v is None:
                    break
                if not OmegaConf.is_config(v):
                    raise KeyError(
                        f"Trying to update key {key}, but {prefix} "
                        f"is not a config, but has type {type(v)}."
                    )
            OmegaConf.update(cfg, key, value, merge=True)

        try:
            from hydra.core.override_parser.overrides_parser import OverridesParser

            has_hydra = True
        except ImportError:
            has_hydra = False

        if has_hydra:
            parser = OverridesParser.create()
            overrides = parser.parse_overrides(overrides)
            for o in overrides:
                key = o.key_or_group
                value = o.value()

View on GitHub (pinned to a2f4a8771a)

Solutions

  1. Fix the override path to target the actual leaf key (e.g. 'model.backbone=50' if backbone itself is the depth)
  2. Restructure the config so intermediate nodes are mappings (backbone: {depth: 50})
  3. Load the correct config version that contains the nested structure implied by the override

Example fix

# before
cfg.model.backbone = 50
LazyConfig.apply_overrides(cfg, ["model.backbone.depth=101"])
# after
cfg.model.backbone = {"depth": 50}
LazyConfig.apply_overrides(cfg, ["model.backbone.depth=101"])
Defensive patterns

Strategy: validation

Validate before calling

from omegaconf import OmegaConf
def override_ok(cfg, key):
    parts = key.split('.')
    for i in range(1, len(parts)):
        v = OmegaConf.select(cfg, '.'.join(parts[:i]), default=None)
        if v is not None and not OmegaConf.is_config(v):
            return False
    return True
assert override_ok(cfg, 'model.backbone.depth')

Type guard

def is_descendable(cfg, dotted_key: str) -> bool:
    return override_ok(cfg, dotted_key)

Try / catch

try:
    LazyConfig.apply_overrides(cfg, [opt])
except KeyError as e:
    if "is not a config" in str(e):
        # target the leaf directly instead
        LazyConfig.apply_overrides(cfg, [opt.rsplit('.', 1)[0] + '=' + new_leaf_value])
    else:
        raise

Prevention

When it happens

Trigger: Running with an override like 'model.backbone.depth=101' where cfg.model.backbone is already the integer 50 (a leaf), or overriding 'train.dataset.name=X' when train.dataset is a string.

Common situations: Hydra-style CLI overrides (--config-key=value) hitting configs where earlier nodes are leaves; overriding keys that only exist in a different config version; appending children to non-struct nodes.

Related errors


AI-assisted analysis of facebookresearch/detectron2@a2f4a8771a (2026-08-27). Data as JSON: /api/errors/680c75e3b94f552a. Report an issue: GitHub.