dbt-labs/dbt-core · error
Versions should not be empty
Error message
Versions should not be empty
What it means
Panic "Versions should not be empty" fires in collect_model_version_info when computing the latest version: the `reduce` on numeric_versions (or the fallback max over version_entries) yields None because the collection is empty despite earlier logic implying at least one entry. It selects the highest numeric version string for a versioned model.
Solutions
- Guard the empty case: return an error naming the model when version_entries is empty before reducing.
- Verify the earlier branch condition — if numeric_versions.len() == version_entries.len() and both are 0, reduce panics; require len() > 0 in the condition.
- Check that the versions YAML block parsed into at least one entry.
Example fix
// before
if numeric_versions.len() == version_entries.len() {
numeric_versions.iter().reduce(...).expect("Versions should not be empty")
// after
if !numeric_versions.is_empty() && numeric_versions.len() == version_entries.len() {
numeric_versions.iter().reduce(...).expect("Versions should not be empty") Defensive patterns
Strategy: validation
Validate before calling
// in YAML: ensure at least one version entry exists versions: - v: 1 - v: 2
Type guard
fn has_versions(entries: &[VersionEntry]) -> bool { !entries.is_empty() } Prevention
- Check emptiness explicitly before reduce/max on collections
- Ensure version filtering upstream never empties the list silently
- Return a named model error instead of panicking in resolvers
When it happens
Trigger: A model defines versions where numeric_versions and version_entries end up empty after filtering — e.g., all version entries were filtered out earlier, or `defined_in`/v-defs produced entries that were pruned before this point.
Common situations: YAML with a `versions:` block whose entries are all invalid/non-numeric in an unexpected way; upstream dedup removing every version entry; version parsing changes making numeric_versions.len() == 0 while version_entries also empty.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Adapter must be configured for the parse phase
- Adapter should be available during parse phase
- agate_table
- AgateTable exists
- All snapshot macros should start with 'snapshot_'
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/0606c046e64aa0ff.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-parser/src/resolve/resolve_properties.rs:840
.clone()
.map(|v| match v {
FloatOrString::String(s) => s,
FloatOrString::Number(n) => n.to_string(),
})
.unwrap_or_else(|| {
// Try parsing as numbers first
let numeric_versions: Vec<_> = version_entries
.iter()
.filter_map(|(v, _, _)| v.parse::<f32>().ok())
.collect();
if numeric_versions.len() == version_entries.len() {
// If all versions are numeric, use highest number
numeric_versions
.iter()
.reduce(|a, b| if a > b { a } else { b })
.map(|n| n.to_string())
.expect("Versions should not be empty")
} else {
// Otherwise use lexicographically last
version_entries
.iter()
.map(|(v, _, _)| v)
.max()
.unwrap()
.clone()
}
});
// Find the config for the latest version from existing version entries
let latest_version_config = version_entries
.iter()
.find(|(v, _, _)| v == &latest_version)
.map(|(_, _, config)| config.clone())
.unwrap_or_else(|| Verbatim::from(None));
View on GitHub (pinned to 0267ce9170)