dbt-labs/dbt-core · error

expected to strip prefix

Error message

expected to strip prefix

What it means

`strip_in_dir` joins a base path with an asset path and strips the io.in_dir prefix to produce a dbt-relative `DbtPath`; if the joined path does not actually live under `in_dir`, `Path::strip_prefix` errors and the code panics. This signals an asset whose location is outside the project/target directory — an internal invariant about where artifacts are written being violated.

Solutions

  1. Run dbt from the project root so `in_dir` matches asset base paths
  2. Check the adapter/source that produced the DbtAsset for non-canonical or external paths
  3. Canonicalize/normalize both paths before strip_prefix (handle symlinks and ..)
  4. Capture the failing path with RUST_BACKTRACE=1 and file a bug

Example fix

// before
DbtPath::from(base_path.join(path).strip_prefix(&io.in_dir).expect("expected to strip prefix"))
// after
DbtPath::from(base_path.join(path).strip_prefix(&io.in_dir)
    .map_err(|_| format!("path {:?} is outside in_dir {:?}", base_path.join(path), io.in_dir))?)
Defensive patterns

Strategy: validation

Validate before calling

// check containment before stripping
fn under_dir(base: &Path, dir: &Path) -> bool {
    std::fs::canonicalize(base).ok().or(Some(base.to_path_buf()))
        .map(|p| p.starts_with(dir)).unwrap_or(false)
}
if !under_dir(&base_path.join(path), &io.in_dir) { bail!("asset outside in_dir"); }

Try / catch

match base_path.join(path).strip_prefix(&io.in_dir) {
    Ok(rel) => DbtPath::from(rel.to_path_buf()),
    Err(_) => return Err(format!("path {:?} outside in_dir {:?}", base_path.join(path), io.in_dir)),
}

Prevention

When it happens

Trigger: `strip_in_dir_from_asset` is called with a `DbtAsset` whose `base_path`+`path` resolves outside `io.in_dir` (e.g. an asset recorded with an absolute path from a different dir, symlinked paths, or an in_dir that doesn't match the actual project dir used when the asset was created).

Common situations: Custom adapters writing artifacts to external/absolute locations; running from a different working directory than the project; path normalization differences (symlinks, `..`, UNC/Windows prefixes) making the prefix mismatch.

Related errors


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

Appendix: source

Thrown at crates/dbt-metadata/src/parse_cache.rs:60

    state::{
        CacheState, DbtAsset, DbtState, FileChanges, NodeExecutionState, NodeExecutionStatus,
        NodeStatus, ResolvedNodes, ResolverState,
    },
};
use dbt_yaml::Value;
use std::{
    collections::{HashMap, HashSet},
    ffi::OsStr,
    path::{Path, PathBuf},
    sync::Arc,
};

fn strip_in_dir(io: &IoArgs, base_path: &Path, path: &Path) -> DbtPath {
    DbtPath::from(
        base_path
            .join(path)
            .strip_prefix(&io.in_dir)
            .expect("expected to strip prefix"),
    )
}

fn strip_in_dir_from_asset(io: &IoArgs, asset: &DbtAsset) -> DbtPath {
    strip_in_dir(io, &asset.base_path, &asset.path)
}

fn is_asset_unchanged(io: &IoArgs, asset: &DbtAsset, unchanged_files: &HashSet<DbtPath>) -> bool {
    let rel_path = strip_in_dir_from_asset(io, asset);
    unchanged_files.contains(&rel_path)
}

fn drop_unchanged_nodes_from_assets(
    io: &IoArgs,
    unchanged_files: &HashSet<DbtPath>,
    assets: &mut Vec<DbtAsset>,
) {
    assets.retain(|asset| !is_asset_unchanged(io, asset, unchanged_files));

View on GitHub (pinned to 0267ce9170)