{"record":{"id":"8a26add7273c2f1d","repo":"can1357/oh-my-pi","slug":"backing-up-might-destroy-source-not-moved","errorCode":null,"errorMessage":"backing up {} might destroy source;  {} not moved","messagePattern":"backing up (.+?) might destroy source;  (.+?) not moved","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/mv.rs","lineNumber":568,"sourceCode":"\t}\n}\n\nfn parse_paths(files: &[OsString], opts: &Options) -> Vec<PathBuf> {\n\tlet paths = files.iter().map(Path::new);\n\n\tif opts.strip_slashes {\n\t\tpaths\n\t\t\t.map(|p| p.components().as_path().to_owned())\n\t\t\t.collect::<Vec<PathBuf>>()\n\t} else {\n\t\tpaths.map(ToOwned::to_owned).collect::<Vec<PathBuf>>()\n\t}\n}\n\nfn handle_two_paths(host: &mut Host, source: &Path, target: &Path, opts: &Options) -> MvResult<()> {\n\tif opts.backup == BackupMode::Simple && source_is_target_backup(source, target, &opts.suffix) {\n\t\treturn Err(\n\t\t\tio::Error::new(\n\t\t\t\tio::ErrorKind::NotFound,\n\t\t\t\tformat!(\n\t\t\t\t\t\"backing up {} might destroy source;  {} not moved\",\n\t\t\t\t\ttarget.quote(),\n\t\t\t\t\tsource.quote()\n\t\t\t\t),\n\t\t\t)\n\t\t\t.into(),\n\t\t);\n\t}\n\n\tlet source_fs = host.resolve(source);\n\tlet target_fs = host.resolve(target);\n\n\tif source_fs.symlink_metadata().is_err() {\n\t\treturn Err(if path_ends_with_terminator(source) {\n\t\t\tMvError::CannotStatNotADirectory(source.quote().to_string()).into()\n\t\t} else {","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/mv.rs#L550-L586","documentation":"Raised by handle_two_paths when `mv --backup=numbered/simple` (BackupMode::Simple) would overwrite the backup copy of the source with the source itself. If the target path is exactly what the source's backup file would be named (source + backup suffix), performing the move-and-back-up would first back the target up over the source, destroying it. The library refuses with `backing up 'X' might destroy source; 'Y' not moved` (note the deliberate double space, matching GNU coreutils) and moves nothing.","triggerScenarios":"Running `mv --b=simple foo foo~` (with default suffix `~`), i.e. mv foo foo~, or any invocation where source_is_target_backup(source, target, suffix) is true: the target equals source plus the configured --suffix, while simple backup mode is active.","commonSituations":"Shell globs or loops that accidentally pair a file with its own backup name (`mv $f $f~` in a cleanup loop); scripted editor-style backups where suffix logic collides with the actual filename; users accustomed to `cp --backup` trying the same pattern with mv.","solutions":["Rename the source to a target that is not source+suffix, or use a different --suffix value","Drop the --backup / --b=simple flag for this invocation since you do not need a backup when the name is already backup-shaped","Check the command's arguments for glob expansion pairing a file with its backup twin (ls to confirm both exist)","Use numbered backups (--backup=numbered) if you genuinely need both copies preserved"],"exampleFix":"// before\nmv --b=simple config.yaml config.yaml~\n// error: backing up 'config.yaml~' might destroy source;  'config.yaml' not moved\n// after\nmv --b=simple config.yaml config.yaml.bak\n// or: mv config.yaml config.yaml~  (no --backup flag)","handlingStrategy":"validation","validationCode":"// refuse the dangerous pairing before invoking mv\nconst suffix = \"~\";\nif (useSimpleBackup && dest === src + suffix) {\n  throw new Error(`refusing: backing up '${dest}' might destroy source '${src}'`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await run(\"mv\", [\"--b=simple\", src, dest]);\n} catch (err) {\n  if (String(err.stderr).includes(\"might destroy source\")) {\n    // retry without backup mode or with a different suffix\n    await run(\"mv\", [src, dest]);\n  } else throw err;\n}","preventionTips":["Never let globs pair a file with its own backup name in a single mv invocation","Use a distinctive --suffix that cannot collide with real filenames","Prefer --backup=numbered when both source and backup must survive","Dry-run loop bodies with `echo mv ...` before executing bulk renames"],"tags":["mv","backup","filesystem","data-loss-prevention"],"backgroundTag":"mv-backup-source-destroyed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}