uutils/coreutils · error · std::io::Error
mv-error-backup-might-destroy-source
Error message
mv-error-backup-might-destroy-source
What it means
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.
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
Example fix
// before mv --suffix=.bak notes.txt notes.txt.bak // after mv --suffix=.bak notes.txt.bak notes.txt # restore direction, or drop -b when moving onto the suffixed name
Defensive patterns
Strategy: validation
Validate before calling
# refuse when dest == source + backup suffix
suffix=.bak; [ "$dest" = "$src$suffix" ] && [ -n "$backup" ] && { echo "backup would destroy source" >&2; exit 1; } Type guard
fn backup_safe(src: &str, dest: &str, suffix: &str, backup: bool) -> bool {
!backup || dest != format!("{src}{suffix}")
} Try / catch
match mv_result {
Err(e) if e.to_string().contains("might destroy source") => {
eprintln!("destination collides with backup of source; pick another name");
}
r => r?,
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- mv-error-dangling-symlink
- mv-error-directory-not-empty
- could not allocate a unique temp name in destination…
- invalid destination path
- invalid value
AI-assisted analysis of uutils/coreutils@92995feca2 (2026-09-20).
Data as JSON: /api/errors/d2c4eef3a6f4b23f.
Report an issue: GitHub.
Appendix: source
Thrown at src/uu/mv/src/mv.rs:393
}
}
fn parse_paths(files: &[OsString], opts: &Options) -> Vec<PathBuf> {
let paths = files.iter().map(Path::new);
if opts.strip_slashes {
paths
.map(|p| p.components().as_path().to_owned())
.collect::<Vec<PathBuf>>()
} else {
paths.map(ToOwned::to_owned).collect::<Vec<PathBuf>>()
}
}
fn handle_two_paths(source: &Path, target: &Path, opts: &Options) -> UResult<()> {
// `mv` never follows a symlink source, so the guard must not either.
if backup_would_destroy_source(source, target, &opts.suffix, opts.backup, false) {
return Err(io::Error::new(
io::ErrorKind::NotFound,
translate!("mv-error-backup-might-destroy-source", "target" => target.quote(), "source" => source.quote()),
)
.into());
}
let Ok(source_metadata) = source.symlink_metadata() else {
return Err(if path_ends_with_terminator(source) {
MvError::CannotStatNotADirectory(source.quote().to_string()).into()
} else {
MvError::NoSuchFile(source.quote().to_string()).into()
});
};
// `symlink_metadata` does not follow symlinks, so this is equivalent to
// `source.is_dir() && !source.is_symlink()` without the extra `stat` calls.
let source_is_dir = source_metadata.is_dir();
let target_is_dir = match target.symlink_metadata() {
Ok(metadata) if metadata.is_symlink() => fs::canonicalize(target).is_ok_and(|p| p.is_dir()),View on GitHub (pinned to 92995feca2)