uutils/coreutils · error · io::Error

no unique temporary name available in the destination…

Error message

no unique temporary name available in the destination directory

What it means

When creating the temporary link name inside the destination directory, replace_link retries on AlreadyExists a bounded number of times. If every candidate name collides, it gives up and returns 'no unique temporary name available in the destination directory' as an AlreadyExists error.

Solutions

  1. Clean up stale temporary links in the destination directory
  2. Retry the operation (transient race conditions usually resolve)
  3. Ensure the process has write permission in the destination directory so renames succeed
Defensive patterns

Strategy: retry

Try / catch

match replace_link(src, dest) {
    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => {
        // transient collision; clean temp links and retry once
        cleanup_temp_links(dest.parent().unwrap());
        replace_link(src, dest)?;
    }
    r => r?,
}

Prevention

When it happens

Trigger: replace_link (via handle_copy_mode or link) where repeated temp-name attempts in the destination directory all already exist — practically a pathological directory containing collisions for every attempted name.

Common situations: Extremely cluttered destination directories; adversarial environments where another process races to claim each temp name; extremely restrictive retry counts with high collision rates.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of uutils/coreutils@92995feca2 (2026-09-20). Data as JSON: /api/errors/6dfc4daea0f92cbf. Report an issue: GitHub.

Appendix: source

Thrown at src/uucore/src/lib/features/fs.rs:1159

            urandom.read_exact(&mut raw)?;
            for (slot, byte) in name[2..].iter_mut().zip(raw) {
                *slot = ALPHABET[byte as usize % ALPHABET.len()];
            }
            let tmp = OsStr::from_bytes(&name);

            match link_at(target, &dir, tmp, symbolic) {
                Ok(()) => {
                    let renamed = renameat(&dir, tmp, &dir, basename);
                    // Renaming onto an existing link to the same inode is a
                    // no-op, which leaves the temp behind.
                    let _ = unlinkat(&dir, tmp, AtFlags::empty());
                    return renamed.map_err(Into::into);
                }
                Err(e) if e.kind() == ErrorKind::AlreadyExists => {}
                Err(e) => return Err(e),
            }
        }
        Err(Error::new(
            ErrorKind::AlreadyExists,
            "no unique temporary name available in the destination directory",
        ))
    }
    #[cfg(not(all(unix, not(target_os = "redox"))))]
    {
        // No atomic replace available here; this leaves the window described
        // above, accepted only where the platform offers nothing better.
        match create_link_std(target, dest, symbolic) {
            Err(e) if e.kind() == ErrorKind::AlreadyExists => {
                fs::remove_file(dest)?;
                create_link_std(target, dest, symbolic)
            }
            res => res,
        }
    }
}

View on GitHub (pinned to 92995feca2)