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
- Run dbt from the project root so `in_dir` matches asset base paths
- Check the adapter/source that produced the DbtAsset for non-canonical or external paths
- Canonicalize/normalize both paths before strip_prefix (handle symlinks and ..)
- 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
- Always run dbt from the project root
- Canonicalize paths (resolve symlinks and ..) before comparing
- Ensure adapters write artifacts under the project/target directory
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
- File name can't be empty
- Adapter must be configured for the parse phase
- Adapter should be available during parse phase
- adapter should be configured for the parse phase
- agate_table
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)