dbt-labs/dbt-core · error

All snapshot macros should start with 'snapshot_'

Error message

All snapshot macros should start with 'snapshot_'

What it means

This is a Rust panic raised by `str::strip_prefix(...).expect(...)` while converting internal 'snapshot.*' macros back into snapshot .sql files during parse-time resolution of a package's snapshots. The parser assumes every macro whose uid starts with `snapshot.` also has a macro *name* starting with the `snapshot_` prefix, so the derived snapshot name (the macro name minus that prefix) can be used as the output filename `snapshots/<name>.sql`. If a snapshot macro's name lacks the prefix, the invariant is broken and the parser panics instead of silently producing a misnamed file.

Source

Thrown at crates/dbt-parser/src/resolve/resolve_snapshots.rs:140

        stdfs::create_dir_all(&snapshots_dir)?;
    }

    // Save snapshots to the `snapshots` directory
    let mut snapshot_files = Vec::new();
    let mut sql_defined_snapshots = Vec::new();
    // Map target path to original macro path for checksum recalculation
    let mut snapshot_original_paths: HashMap<PathBuf, PathBuf> = HashMap::new();
    let default_snapshots_path = vec![DBT_SNAPSHOTS_DIR_NAME.to_string()];
    let mut synthetic_snapshot_macro_uids: HashSet<String> = HashSet::new();
    for (macro_uid, macro_node) in macros {
        if macro_node.package_name == package_name && macro_uid.starts_with("snapshot.") {
            synthetic_snapshot_macro_uids.insert(macro_uid.clone());
            // Write the macro call to the `snapshots` directory
            let macro_call = format!("{{{{ {}() }}}}", macro_node.name);
            let macro_name = macro_node.name.clone();
            let snapshot_name = macro_name
                .strip_prefix("snapshot_")
                .expect("All snapshot macros should start with 'snapshot_'")
                .to_string();

            // Preserve file layout for proper fqn generation
            let original_relative_path = strip_resource_paths_from_ref_path(
                &macro_node.path,
                package
                    .dbt_project
                    .snapshot_paths
                    .as_ref()
                    .unwrap_or(&default_snapshots_path),
            );

            let target_path = PathBuf::from(DBT_SNAPSHOTS_DIR_NAME)
                .join(original_relative_path.with_file_name(format!("{snapshot_name}.sql")));
            let snapshot_path = arg.io.out_dir.join(&target_path);
            if let Some(parent) = snapshot_path.parent() {
                stdfs::create_dir_all(parent)?;
            }

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Rename the offending macro so its name starts with `snapshot_` (the snapshot file will then be emitted as `snapshots/<name-without-prefix>.sql`)
  2. Check for a stale `target/` directory and delete it so macros are re-parsed from source rather than from a stale manifest
  3. If the macro is not a real snapshot, move it out of the snapshot path/namespace so its uid no longer starts with `snapshot.`
  4. If this comes from a third-party package, report/patch the package or pin a version whose snapshot macros follow the `snapshot_` naming convention

Example fix

// before: macro name without required prefix
{% macro my_snapshot() %} ... {% endmacro %}

// after
{% macro snapshot_my_snapshot() %} ... {% endmacro %}
Defensive patterns

Strategy: validation

Validate before calling

// before invoking the parser / in CI
for macro_node in snapshot_macros {
    if macro_node.uid.starts_with("snapshot.") && !macro_node.name.starts_with("snapshot_") {
        return Err(format!("snapshot macro '{}' must be named 'snapshot_*'", macro_node.name));
    }
}

Type guard

fn is_valid_snapshot_macro(name: &str) -> bool {
    name.starts_with("snapshot_") && name.len() > "snapshot_".len()
}

Prevention

When it happens

Trigger: Running `dbt parse`/a build when a macro with uid starting `snapshot.` in the target package has a name that does not begin with `snapshot_` — e.g. a user-defined macro named like a snapshot (uid `snapshot.<pkg>.<name>` where name lacks the `snapshot_` prefix), a hand-edited or stale `target/` manifest, or an adapter/tool that synthesizes snapshot macros with an unexpected naming scheme.

Common situations: Users renaming a snapshot macro file or macro name without keeping the `snapshot_` prefix; packages written for other dbt tooling that name snapshot macros differently; generated/templated macros from scripts; upgrading a project that previously had a custom snapshot-naming convention into this parser.

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/1dbdaeff040238ac. Report an issue: GitHub.