denoland/deno · error
the source and destination are the same file
Error message
the source and destination are the same file
What it means
Before dispatching a copy, Deno lstats both paths and compares identity with is_identical(): inode equality on Unix; on Windows creation_time + last_write_time equality (a heuristic, since a stable file_index() is not exposed by std). On a match it refuses with io::ErrorKind::InvalidInput 'the source and destination are the same file' (ext/fs/std_fs.rs:918).
Source
Thrown at ext/fs/std_fs.rs:918
{
return cp_(
source_meta,
from,
&to.join(from.file_name().ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"the source path is not a valid file",
)
})?),
);
}
}
if let Ok(m) = fs::symlink_metadata(to)
&& is_identical(&source_meta, &m)
{
return Err(
io::Error::new(
io::ErrorKind::InvalidInput,
"the source and destination are the same file",
)
.into(),
);
}
cp_(source_meta, from, to)
}
#[cfg(not(windows))]
fn stat(path: &Path) -> FsResult<FsStat> {
let metadata = fs::metadata(path)?;
Ok(FsStat::from_std(metadata))
}
#[cfg(windows)]
fn stat(path: &Path) -> FsResult<FsStat> {View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Skip when the paths truly are the same file: compare Deno.realPathSync(from) === Deno.realPathSync(to)
- On Windows false positives: remove the stale destination first (Deno.removeSync(to)) so the metadata comparison no longer matches
- Compare size/content hash yourself when timestamps are suspect
- If distinct files keep being flagged, report it — the Windows check is time-based by design
Example fix
// before
await Deno.copy(src, dst); // false positive: same timestamps on Windows
// after
if (Deno.build.os === 'windows') {
try { Deno.removeSync(dst); } catch { /* not present */ }
}
await Deno.copy(src, dst); Defensive patterns
Strategy: validation
Validate before calling
function sameRealPath(from: string, to: string): boolean {
try {
return Deno.realPathSync(from) === Deno.realPathSync(to);
} catch {
return false;
}
}
if (!sameRealPath(src, dst)) {
if (Deno.build.os === 'windows') {
try { Deno.removeSync(dst); } catch { /* absent */ } // defeat timestamp heuristic
}
await Deno.copy(src, dst);
} Try / catch
try {
await Deno.copy(src, dst);
} catch (e) {
if (e instanceof Error && /the same file/.test(e.message)) {
// distinguish real duplicates (same realPath) from Windows timestamp false positives
if (Deno.realPathSync(src) === Deno.realPathSync(dst)) return;
Deno.removeSync(dst);
await Deno.copy(src, dst);
return;
}
throw e;
} Prevention
- Compare realPathSync of source and destination before copying
- On Windows, remove the stale destination first — the same-file check compares timestamps
- Watch for hard links/symlinks making distinct-looking paths the same inode
When it happens
Trigger: Destination is a hard link or symlink to the source (same inode on Unix); equivalent path spellings; on Windows, the timestamp heuristic can misfire on two genuinely different files that share creation and modification times — e.g. files extracted from the same archive or emitted by one code-generator run.
Common situations: Copy scripts where TO is inside FROM through links; CI artifacts with mass-identical timestamps; false positives reported on Windows after zip extraction preserves mtimes.
Related errors
- Source and destination paths refer to the same file
- the source path is not a valid file
- On Windows the target must be a file or directory
- ERR_FS_INVALID_SYMLINK_TYPE
- ERR_INCOMPATIBLE_OPTION_PAIR
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/174475bb2e4d2706.
Report an issue: GitHub.