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
- Use `.ok_or_else(...)` or skip when the entry is missing instead of expect, logging a warning naming the model.
- Ensure both maps are built from the same source list so keying stays consistent (same name normalization).
- 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
- Build minimal_model_properties and typed_models_properties from the same source list
- Normalize versioned vs base model names identically in both maps
- Prefer skip-with-warning over expect for per-model resolution
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
- Error message always present on ShouldBe::ButIsnt variant
- Error always present on ShouldBe::ButIsnt variant
- conversion_type_params must exist for conversion metric
- Schema not found for canonical FQN: {}
- `EnterGuard` values dropped out of order. Guards returned by
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/2b296b0a5489daf0.
Report an issue: GitHub.