denoland/deno · error · FsError
Source and destination paths refer to the same file
Error message
Source and destination paths refer to the same file
What it means
copy_file() guards against copying a file onto itself: opening the destination with truncation before reading the source would silently empty the file, so Deno compares file identity with same_file::is_same_file (device + inode on Unix, file index + volume serial on Windows) and, if identical, returns io::ErrorKind::InvalidInput 'Source and destination paths refer to the same file' — matching cp behavior and libuv's message.
Source
Thrown at ext/fs/std_fs.rs:664
res.map_err(Into::into)
}
fn copy_file(from: &Path, to: &Path) -> FsResult<()> {
// Guard against copying a file onto itself. Otherwise the destination is
// opened with truncation (or unlinked) before the source is read, which
// silently empties the file. Match `cp` behavior and error instead.
//
// `same_file::is_same_file` compares the file identity (device + inode on
// Unix, file index + volume serial via the open handle on Windows) using a
// single stat per path, rather than fully canonicalizing both paths which
// would `lstat`/`readlink` every component twice. It still catches
// equivalent paths such as `./`, `..`, symlinks and hard links, and returns
// `Err` (treated as "not the same file") in the common case where the
// destination does not yet exist.
if same_file::is_same_file(from, to).unwrap_or(false) {
return Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"Source and destination paths refer to the same file",
)
.into(),
);
}
#[cfg(target_os = "macos")]
{
use std::ffi::CString;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::fs::PermissionsExt;
use libc::clonefile;
use libc::stat;
use libc::unlink;
let from_str = CString::new(from.as_os_str().as_encoded_bytes())View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Compare resolved paths first: skip when Deno.realPathSync(from) === Deno.realPathSync(to)
- Skip the call when the two argument strings are equal
- If you intended an overwrite workflow, delete the destination explicitly instead of copying onto itself
- Audit symlink/hardlink layouts when from and to look different but resolve identically
Example fix
// before
Deno.copyFileSync(fromPath, toPath);
// after
if (Deno.realPathSync(fromPath) !== Deno.realPathSync(toPath)) {
Deno.copyFileSync(fromPath, toPath);
} Defensive patterns
Strategy: validation
Validate before calling
function copyFileSyncIfDifferent(from: string, to: string): void {
let fromReal: string, toReal: string;
try {
fromReal = Deno.realPathSync(from);
} catch {
throw new Error(`Source does not exist: ${from}`);
}
try {
toReal = Deno.realPathSync(to);
} catch {
Deno.copyFileSync(from, to); // destination absent: safe
return;
}
if (fromReal === toReal) return; // same inode: skip
Deno.copyFileSync(from, to);
} Type guard
function isSamePath(from: string, to: string): boolean {
try {
return Deno.realPathSync(from) === Deno.realPathSync(to);
} catch {
return false; // missing destination cannot be the same file
}
} Try / catch
try {
Deno.copyFileSync(from, to);
} catch (e) {
if (e instanceof Error && /refer to the same file/.test(e.message)) return;
throw e;
} Prevention
- Compare realPathSync of both arguments before copying
- Validate FROM/TO parameters (env vars, CLI args) are distinct strings
- Remember hard links and symlinks resolve to the same inode — path equality checks are not enough
When it happens
Trigger: Deno.copyFileSync('a.txt', 'a.txt'); destination is a symlink or hard link resolving to the source inode (copyFileSync('a.txt', 'link-to-a.txt')); equivalent spellings like './a.txt' vs 'a.txt'; paths through symlinked directories that land on the same file.
Common situations: Backup scripts whose glob results include the destination; FROM/TO parameters mistakenly set to the same value; symlinked config or cache directories making two different strings the same file.
Related errors
- the source and destination are the same file
- ERR_INCOMPATIBLE_OPTION_PAIR
- the source path is not a valid file
- On Windows the target must be a file or directory
- ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/e45e85f6007ab643.
Report an issue: GitHub.