{"record":{"id":"7e4fff9338c39d3b","repo":"dbt-labs/dbt-core","slug":"expected-to-strip-prefix","errorCode":null,"errorMessage":"expected to strip prefix","messagePattern":"expected to strip prefix","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-metadata/src/parse_cache.rs","lineNumber":60,"sourceCode":"    state::{\n        CacheState, DbtAsset, DbtState, FileChanges, NodeExecutionState, NodeExecutionStatus,\n        NodeStatus, ResolvedNodes, ResolverState,\n    },\n};\nuse dbt_yaml::Value;\nuse std::{\n    collections::{HashMap, HashSet},\n    ffi::OsStr,\n    path::{Path, PathBuf},\n    sync::Arc,\n};\n\nfn strip_in_dir(io: &IoArgs, base_path: &Path, path: &Path) -> DbtPath {\n    DbtPath::from(\n        base_path\n            .join(path)\n            .strip_prefix(&io.in_dir)\n            .expect(\"expected to strip prefix\"),\n    )\n}\n\nfn strip_in_dir_from_asset(io: &IoArgs, asset: &DbtAsset) -> DbtPath {\n    strip_in_dir(io, &asset.base_path, &asset.path)\n}\n\nfn is_asset_unchanged(io: &IoArgs, asset: &DbtAsset, unchanged_files: &HashSet<DbtPath>) -> bool {\n    let rel_path = strip_in_dir_from_asset(io, asset);\n    unchanged_files.contains(&rel_path)\n}\n\nfn drop_unchanged_nodes_from_assets(\n    io: &IoArgs,\n    unchanged_files: &HashSet<DbtPath>,\n    assets: &mut Vec<DbtAsset>,\n) {\n    assets.retain(|asset| !is_asset_unchanged(io, asset, unchanged_files));","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-metadata/src/parse_cache.rs#L42-L78","documentation":"`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.","triggerScenarios":"`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).","commonSituations":"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.","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"],"exampleFix":"// before\nDbtPath::from(base_path.join(path).strip_prefix(&io.in_dir).expect(\"expected to strip prefix\"))\n// after\nDbtPath::from(base_path.join(path).strip_prefix(&io.in_dir)\n    .map_err(|_| format!(\"path {:?} is outside in_dir {:?}\", base_path.join(path), io.in_dir))?)","handlingStrategy":"validation","validationCode":"// check containment before stripping\nfn under_dir(base: &Path, dir: &Path) -> bool {\n    std::fs::canonicalize(base).ok().or(Some(base.to_path_buf()))\n        .map(|p| p.starts_with(dir)).unwrap_or(false)\n}\nif !under_dir(&base_path.join(path), &io.in_dir) { bail!(\"asset outside in_dir\"); }","typeGuard":null,"tryCatchPattern":"match base_path.join(path).strip_prefix(&io.in_dir) {\n    Ok(rel) => DbtPath::from(rel.to_path_buf()),\n    Err(_) => return Err(format!(\"path {:?} outside in_dir {:?}\", base_path.join(path), io.in_dir)),\n}","preventionTips":["Always run dbt from the project root","Canonicalize paths (resolve symlinks and ..) before comparing","Ensure adapters write artifacts under the project/target directory"],"tags":["paths","filesystem","panic"],"backgroundTag":"path-not-relative-to-directory","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}