denoland/deno · error
the source path is not a valid file
Error message
the source path is not a valid file
What it means
In Deno.copy()/copySync(), when the destination is an existing directory and the source is not a directory, Deno copies into dest/from.file_name(). If the source path has no final component — it terminates in '..' or is a filesystem root — file_name() returns None and the copy fails with io::ErrorKind::InvalidInput 'the source path is not a valid file' (ext/fs/std_fs.rs:905).
Source
Thrown at ext/fs/std_fs.rs:905
// && source_meta.volume_serial_number()
// == dest_meta.volume_serial_number()
source_meta.last_write_time() == dest_meta.last_write_time()
&& source_meta.creation_time() == dest_meta.creation_time()
}
}
if let Ok(m) = fs::metadata(to)
&& m.is_dir()
{
// Only target sub dir when source is not a dir itself
if let Ok(from_meta) = fs::metadata(from)
&& !from_meta.is_dir()
{
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(),
);View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Normalize the source with Deno.realPathSync(from) before copying
- Validate the source has a real file-name component: from.split('/').pop() not in ['', '.', '..']
- Handle directories and files with separate branches instead of relying on dest-dir dispatch
Example fix
// before
Deno.copySync(`${dir}/..`, destDir);
// after
const from = Deno.realPathSync(dir);
Deno.copySync(from, destDir); Defensive patterns
Strategy: validation
Validate before calling
function normalizeCopySource(from: string): string {
const real = Deno.realPathSync(from); // resolves '..' and symlink segments
const name = real.split('/').pop() ?? '';
if (name === '' || name === '.' || name === '..') {
throw new Error(`Copy source has no file-name component: ${from}`);
}
return real;
} Type guard
function hasFileNameComponent(p: string): boolean {
const name = p.split('/').pop() ?? '';
return name !== '' && name !== '.' && name !== '..';
} Prevention
- Normalize source paths with realPathSync before Deno.copy
- Never assemble copy sources by appending '..'
- Handle directories and files in separate branches instead of relying on dest-dir dispatch
When it happens
Trigger: A source path whose literal form ends in '..' (e.g. 'data/..') or is a root ('/') while the destination exists as a directory and fs::metadata resolves the source to a non-directory (reachable mainly through symlink chains, since a literal '..' usually resolves to a directory).
Common situations: Path-joining bugs that append '..' to a source; passing a resolved parent or cwd as the source; scripts assembling paths from user input without normalization.
Related errors
- Source and destination paths refer to the same file
- sockets cannot be copied
- the source and destination are the same file
- On Windows the target must be a file or directory
- ERR_FS_CP_EINVAL
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/745b667dc94c301e.
Report an issue: GitHub.