{"record":{"id":"3fd62ca83a6c3589","repo":"uutils/coreutils","slug":"mv-error-inter-device-move-failed","errorCode":null,"errorMessage":"mv-error-inter-device-move-failed","messagePattern":"mv-error-inter-device-move-failed","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"src/uu/mv/src/mv.rs","lineNumber":1442,"sourceCode":"        }\n        // Preserve ownership (uid/gid) from the source\n        let _ = preserve_ownership(from, to);\n    }\n\n    Ok(())\n}\n\nfn rename_file_fallback(\n    from: &Path,\n    to: &Path,\n    #[cfg(unix)] hardlink_tracker: Option<&mut HardlinkTracker>,\n    #[cfg(unix)] hardlink_scanner: Option<&HardlinkGroupScanner>,\n) -> io::Result<()> {\n    // Remove existing target file if it exists\n    if to.is_symlink() {\n        fs::remove_file(to).map_err(|err| {\n            let inter_device_msg = translate!(\"mv-error-inter-device-move-failed\", \"from\" => from.quote(), \"to\" => to.quote(), \"err\" => err);\n            io::Error::new(err.kind(), inter_device_msg)\n        })?;\n    } else if to.exists() {\n        // For non-symlinks, just remove the file without special error handling\n        fs::remove_file(to)?;\n    }\n\n    // Check if this file is part of a hardlink group and if so, create a hardlink instead of copying\n    #[cfg(unix)]\n    {\n        if let (Some(tracker), Some(scanner)) = (hardlink_tracker, hardlink_scanner) {\n            use crate::hardlink::HardlinkOptions;\n            let hardlink_options = HardlinkOptions::default();\n            if let Some(existing_target) =\n                tracker.check_hardlink(from, to, scanner, &hardlink_options)\n            {\n                // Create a hardlink to the first moved file instead of copying\n                fs::hard_link(&existing_target, to)?;\n                fs::remove_file(from)?;","sourceCodeStart":1424,"sourceCodeEnd":1460,"githubUrl":"https://github.com/uutils/coreutils/blob/85295bbf788bfd7a6926ba692031563504b304b7/src/uu/mv/src/mv.rs#L1424-L1460","documentation":"In rename_file_fallback, when the destination is a symlink, mv first removes it before copying the real file. If that remove fails, the error is re-wrapped with the localized inter-device move message including from, to and the underlying OS error, preserving the original io::ErrorKind. It indicates the cross-device rename fallback could not even clear the existing destination symlink.","triggerScenarios":"`mv file dest_symlink` where rename fails (EXDEV/cross-device), the fallback tries fs::remove_file(dest_symlink), and the unlink fails — e.g. destination is on a read-only or protected mount, sticky-bit directory not owned by the user, or the link disappeared/was replaced concurrently.","commonSituations":"Moving onto a symlink in a /tmp-like sticky directory owned by another user; destination filesystem mounted read-only; immutable attribute (chattr +i) on the destination; SELinux/AppArmor denials on unlink.","solutions":["Read the wrapped `err` for the real cause (EPERM/EACCES/EROFS) and fix permissions or remount read-write.","Remove the destination symlink manually, then re-run mv.","Check for immutable flags (`lsattr`, `chattr -i`) or MAC policy denials in audit logs.","Verify you own the destination directory (sticky bit requires ownership of the link)."],"exampleFix":"// before\nmv bigfile /mnt/ro/link   // dest on read-only mount\n// after\nsudo mount -o remount,rw /mnt && mv bigfile /mnt/link","handlingStrategy":"try-catch","validationCode":"let meta = dest.symlink_metadata()?;\nif meta.file_type().is_symlink() {\n    // test unlinkability up front\n    if std::fs::remove_file(dest).is_err() {\n        eprintln!(\"cannot remove existing dest symlink; fix perms first\");\n    }\n}","typeGuard":"fn is_symlink(p: &Path) -> bool {\n    p.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false)\n}","tryCatchPattern":"match mv_result {\n    Err(e) => eprintln!(\"mv fallback failed removing dest symlink: {e} (kind={:?})\", e.kind()),\n    Ok(_) => {}\n}","preventionTips":["Ensure you own destination directories with sticky bits","Avoid read-only/immutable destinations (check lsattr, mount flags)","Pre-remove conflicting symlinks before scripted moves"],"tags":["mv","filesystem","permissions","symlink"],"backgroundTag":"inter-device-move-failed","analyzedSha":"85295bbf788bfd7a6926ba692031563504b304b7","analyzedAt":"2026-08-31T11:11:36.175Z","contentChangedAt":"2026-08-31T11:11:36.175Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}