dbt-labs/dbt-core · error

ModelPropertiesEntry guaranteed to exist for model

Error message

ModelPropertiesEntry guaranteed to exist for model

What it means

Panic "ModelPropertiesEntry guaranteed to exist for model" occurs in resolve_nested_model_metrics when `minimal_model_properties.get(model_name)` returns None for a model whose metrics are non-none. The resolver assumes every model iterated from typed_models_properties has a matching entry in minimal_model_properties; divergence between the two collections breaks the invariant.

Source

Thrown at crates/dbt-parser/src/resolve/resolve_metrics.rs:163

            init_project_config(
                &package.dbt_project.metrics,
                (),
                dependency_package_name,
                disallow_plus_prefix,
                adapter_type,
            )
        },
        adapter_type,
    )?;

    for (model_name, model_props) in typed_models_properties.iter() {
        if model_props.metrics.is_none() {
            continue;
        }

        let mpe = minimal_model_properties
            .get(model_name)
            .expect("ModelPropertiesEntry guaranteed to exist for model");

        // For versioned models, `typed_models_properties` contains one entry per
        // version plus a canonical entry keyed by `mpe.name` pointing at the
        // latest version. Process only the canonical entry to avoid emitting
        // duplicate-metric-name errors for a single YAML declaration.
        if mpe.version_info.is_some() && model_name != &mpe.name {
            continue;
        }

        let mut semantic_model_name = model_props.name.clone();
        if let Some(semantic_model) = &model_props.semantic_model
            && let Some(name) = &semantic_model.name
        {
            semantic_model_name = name.clone();
        }
        let semantic_model_unique_id =
            get_unique_id(&semantic_model_name, package_name, None, "semantic_model");

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Use `.ok_or_else(...)` or skip when the entry is missing instead of expect, logging a warning naming the model.
  2. Ensure both maps are built from the same source list so keying stays consistent (same name normalization).
  3. Check the versioned-model handling above: only process the canonical entry keyed by mpe.name.

Example fix

// before
let mpe = minimal_model_properties.get(model_name).expect("ModelPropertiesEntry guaranteed to exist for model");
// after
let mpe = match minimal_model_properties.get(model_name) {
    Some(mpe) => mpe,
    None => continue,
};
Defensive patterns

Strategy: fallback

Validate before calling

// before resolving, ensure both collections agree
for model in &models_with_metrics {
    debug_assert!(minimal_model_properties.contains_key(model), "missing MPE for {}", model);
}

Type guard

fn mpe_of<'a>(map: &'a HashMap<String, ModelPropertiesEntry>, name: &str) -> Option<&'a ModelPropertiesEntry> { map.get(name) }

Try / catch

// for library users hitting the panic via resolve_metrics, wrap and surface
let res = std::panic::catch_unwind(|| resolve_metrics(...));

Prevention

When it happens

Trigger: resolve_metrics processes a model present in the models/metrics input list but absent from minimal_model_properties — e.g., the model's YAML entry was keyed under a versioned name or its properties were filtered out upstream.

Common situations: Versioned models where the map is keyed by versioned name vs base name; duplicated YAML files for the same model where one populates typed_models_properties but not minimal_model_properties.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/2b296b0a5489daf0. Report an issue: GitHub.