{"record":{"id":"d2c4eef3a6f4b23f","repo":"uutils/coreutils","slug":"mv-error-backup-might-destroy-source","errorCode":null,"errorMessage":"mv-error-backup-might-destroy-source","messagePattern":"mv-error-backup-might-destroy-source","errorType":"error_code","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"src/uu/mv/src/mv.rs","lineNumber":393,"sourceCode":"    }\n}\n\nfn parse_paths(files: &[OsString], opts: &Options) -> Vec<PathBuf> {\n    let paths = files.iter().map(Path::new);\n\n    if opts.strip_slashes {\n        paths\n            .map(|p| p.components().as_path().to_owned())\n            .collect::<Vec<PathBuf>>()\n    } else {\n        paths.map(ToOwned::to_owned).collect::<Vec<PathBuf>>()\n    }\n}\n\nfn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()> {\n    // `mv` never follows a symlink source, so the guard must not either.\n    if backup_would_destroy_source(source, target, &opts.suffix, opts.backup, false) {\n        return Err(io::Error::new(\n            io::ErrorKind::NotFound,\n            translate!(\"mv-error-backup-might-destroy-source\", \"target\" => target.quote(), \"source\" => source.quote()),\n        )\n        .into());\n    }\n    let Ok(source_metadata) = source.symlink_metadata() else {\n        return Err(if path_ends_with_terminator(source) {\n            MvError::CannotStatNotADirectory(source.quote().to_string()).into()\n        } else {\n            MvError::NoSuchFile(source.quote().to_string()).into()\n        });\n    };\n\n    // `symlink_metadata` does not follow symlinks, so this is equivalent to\n    // `source.is_dir() && !source.is_symlink()` without the extra `stat` calls.\n    let source_is_dir = source_metadata.is_dir();\n    let target_is_dir = match target.symlink_metadata() {\n        Ok(metadata) if metadata.is_symlink() => fs::canonicalize(target).is_ok_and(|p| p.is_dir()),","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/uutils/coreutils/blob/92995feca29e324a7c559ede91db81c32d9f5d59/src/uu/mv/src/mv.rs#L375-L411","documentation":"Before moving, `mv` checks whether creating the requested backup would overwrite the source file itself (same name after applying the backup suffix); if so it refuses with this NotFound-kind error, since the backup step would destroy the file being moved.","triggerScenarios":"`mv --backup` (or -b) where the target path differs from source only by the backup suffix, e.g. `mv --suffix=.bak file file.bak` styles, or moving `a` onto `a~` when suffix is `~` and a backup would be made of `a~` onto itself.","commonSituations":"Scripts that construct destination names by appending the backup suffix to the source, typos where source and target are nearly identical, or restoring files into their backup names with backup mode enabled.","solutions":["Use a destination name that does not collide with source+suffix","Disable backup for this call (drop -b/--backup) so the guard doesn't apply","Choose a different --suffix so backup name != source path","Check spelling: with backup mode you probably meant `mv file.bak file`, not the reverse"],"exampleFix":"// before\nmv --suffix=.bak notes.txt notes.txt.bak\n// after\nmv --suffix=.bak notes.txt.bak notes.txt   # restore direction, or drop -b when moving onto the suffixed name","handlingStrategy":"validation","validationCode":"# refuse when dest == source + backup suffix\nsuffix=.bak; [ \"$dest\" = \"$src$suffix\" ] && [ -n \"$backup\" ] && { echo \"backup would destroy source\" >&2; exit 1; }","typeGuard":"fn backup_safe(src: &str, dest: &str, suffix: &str, backup: bool) -> bool {\n    !backup || dest != format!(\"{src}{suffix}\")\n}","tryCatchPattern":"match mv_result {\n    Err(e) if e.to_string().contains(\"might destroy source\") => {\n        eprintln!(\"destination collides with backup of source; pick another name\");\n    }\n    r => r?,\n}","preventionTips":["Never enable --backup when constructing dest from src + suffix","Double-check source/dest argument order in scripts","Use distinct backup suffixes (--suffix) that cannot collide with real filenames","Test mv commands with -n (no-clobber) first"],"tags":["mv","backup","cli"],"backgroundTag":"resource-not-found","analyzedSha":"92995feca29e324a7c559ede91db81c32d9f5d59","analyzedAt":"2026-09-20T12:39:35.476Z","contentChangedAt":"2026-09-20T12:39:35.476Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}