{"id":"0e5cf1a439303e66","repo":"rust-lang/cargo","slug":"cannot-clean-not-a-directory","errorCode":null,"errorMessage":"cannot clean `{}`: not a directory","messagePattern":"cannot clean `(.+?)`: not a directory","errorType":"exception","errorClass":"AlreadyPrintedError","httpStatus":null,"severity":"error","filePath":"src/ops/cargo_clean.rs","lineNumber":69,"sourceCode":"    let mut target_dir = ws.target_dir();\n    let mut build_dir = ws.build_dir();\n    let gctx = opts.gctx;\n    let mut clean_ctx = CleanContext::new(gctx);\n    clean_ctx.dry_run = opts.dry_run;\n\n    const CLEAN_ABORT_NOTE: &str =\n        \"cleaning has been aborted to prevent accidental deletion of unrelated files\";\n\n    // make sure target_dir is a directory if it exists so that we don't delete files\n    if let Ok(meta) = fs::symlink_metadata(target_dir.as_path_unlocked()) {\n        // do not error if target_dir is symlink; let cargo delete it\n        if !meta.is_symlink() && !meta.is_dir() {\n            let title = format!(\"cannot clean `{}`: not a directory\", target_dir.display());\n            let report = [Level::ERROR\n                .primary_title(title)\n                .element(Level::NOTE.message(CLEAN_ABORT_NOTE))];\n            gctx.shell().print_report(&report, false)?;\n            return Err(crate::AlreadyPrintedError::new(anyhow::anyhow!(\"\")).into());\n        }\n    }\n\n    // do some validation on target_dir if it was specified via --target-dir\n    if opts.explicit_target_dir_arg {\n        let target_dir_path = target_dir.as_path_unlocked();\n\n        // perform validation on target_dir only if it exists and check if the target directory has a valid CACHEDIR.TAG\n        if target_dir_path.exists()\n            && let Err(err) = validate_target_dir_tag(target_dir_path)\n        {\n            // if target_dir was passed explicitly via --target-dir, then hard error if validation fails\n            let title = format!(\"cannot clean `{}`: {err}\", target_dir_path.display());\n            let report = [Level::ERROR\n                .primary_title(title)\n                .element(Level::NOTE.message(CLEAN_ABORT_NOTE))];\n            gctx.shell().print_report(&report, false)?;\n            return Err(crate::AlreadyPrintedError::new(anyhow::anyhow!(\"\")).into());","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/ops/cargo_clean.rs#L51-L87","documentation":"`cargo clean` guards against deleting something that is not actually a build target directory. It stats the configured target dir; if the entry exists, is not a symlink, and is not a directory, it aborts with \"cannot clean `...`: not a directory\" plus a note that cleaning was aborted to prevent accidental deletion of unrelated files. This prevents wiping a regular file that happens to live at the target path.","triggerScenarios":"The resolved target directory path points at a regular file (e.g. someone created a file named `target`, or `--target-dir` points at an existing file), and `cargo clean` is invoked.","commonSituations":"Misconfigured `CARGO_TARGET_DIR` or `--target-dir` pointing at a file, a stale file from a broken setup, or a symlink target replaced by a regular file.","solutions":["Inspect the path with `ls -la <target-dir>` and confirm whether it is a stray file.","Remove or rename the offending file manually if it is safe to do so, then re-run `cargo clean`.","Fix the `CARGO_TARGET_DIR` / `--target-dir` configuration to point at a directory."],"exampleFix":"# before (a regular file named 'target')\n$ ls -la target\n-rw-r--r-- 1 user user 0 ... target\n$ cargo clean   # errors\n\n# after\nrm target\ncargo clean","handlingStrategy":"validation","validationCode":"// Stat the target dir; refuse to clean if it is a non-symlink non-directory entry.\nuse std::path::Path;\nfn target_dir_is_cleanable(path: &Path) -> bool {\n    match std::fs::symlink_metadata(path) {\n        Ok(m) => m.is_symlink() || m.is_dir(),\n        Err(_) => true, // nothing to clean; safe\n    }\n}\n// assert!(target_dir_is_cleanable(&target_dir), \"target path is not a directory\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate `CARGO_TARGET_DIR` / `--target-dir` resolves to a directory in setup scripts.","Never let tooling create a file at the target path.","In CI, clean the workspace in a fresh checkout to avoid stray files."],"tags":["cargo-clean","filesystem","safety","target-dir"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}