uutils/coreutils · error · io::Error

invalid destination path

Error message

invalid destination path

What it means

In the symlink-replacement fallback, mv derives the destination's parent and basename via openat-based atomic replacement. If the destination path has no final component (e.g., it is '.' , '..' , '/' or ends in '..'), to.file_name() returns None and this InvalidInput error is raised. It protects the low-level create_symlink_replace logic from a destination it cannot split into dir + name.

Source

Thrown at src/uu/mv/src/mv.rs:1075

#[cfg(all(unix, not(target_os = "redox")))]
fn create_symlink_replace(target: &Path, to: &Path) -> io::Result<()> {
    use io::Read;
    use rustix::fs::{AtFlags, CWD, Mode, OFlags, openat, renameat, symlinkat, unlinkat};
    use std::ffi::OsStr;
    use std::os::unix::ffi::OsStrExt;

    // GNU's template is `CuXXXXXX`: a 2-char prefix plus 6 random chars
    // drawn from a 62-char alphabet. Modulo bias on a 256→62 mapping is
    // ~3% per slot — irrelevant for an 8-char unguessability budget.
    const ALPHABET: &[u8; 62] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    let parent = to
        .parent()
        .filter(|p| !p.as_os_str().is_empty())
        .unwrap_or_else(|| Path::new("."));
    let basename = to
        .file_name()
        .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "invalid destination path"))?;

    let dir_fd = openat(
        CWD,
        parent,
        OFlags::DIRECTORY | OFlags::RDONLY | OFlags::CLOEXEC | OFlags::NOFOLLOW,
        Mode::empty(),
    )?;

    let mut urandom = fs::File::open("/dev/urandom")?;

    for _ in 0..32 {
        let mut tmp_bytes = *b"Cu------";
        let mut raw = [0u8; 6];
        urandom.read_exact(&mut raw)?;
        for (slot, byte) in tmp_bytes[2..].iter_mut().zip(raw) {
            *slot = ALPHABET[(byte as usize) % ALPHABET.len()];
        }
        let tmp = OsStr::from_bytes(&tmp_bytes);

View on GitHub (pinned to 85295bbf78)

Solutions

  1. Pass a real destination filename, not '.', '..' or the filesystem root
  2. Normalize the destination with `realpath`/canonicalize in scripts before invoking mv
  3. Validate the target in scripts: ensure it has a basename component (e.g., `[ -n "$(basename "$dest")" ]` and dest != . / .. )
  4. If the intent was 'move into directory', drop -T/--no-target-directory and let mv resolve the dir

Example fix

// before
mv -T newlink .
// after
mv -T newlink /path/to/existing-link-name
Defensive patterns

Strategy: validation

Validate before calling

# ensure destination has a basename and is not '.' / '..' / '/'
case "$dest" in
  ""|"."|".."|"/"|".") echo "invalid destination path"; exit 1;;
esac
case "$dest" in *[!/]*/) echo "trailing slash on non-dir target" ;; esac

Try / catch

null

Prevention

When it happens

Trigger: Calling mv with a symlink destination that is a bare directory reference like `mv -T link .`, `mv src ..`, `mv src /`, or a trailing path that normalizes to a directory with no filename.

Common situations: Scripts building destination paths from variables that end up empty or as '.'/'..'; typos with trailing slashes or dot components; using mv -T with directory-valued targets.

Related errors


AI-assisted analysis of uutils/coreutils@85295bbf78 (2026-08-31). Data as JSON: /api/errors/839506a9099b34f7. Report an issue: GitHub.