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

  1. Normalize the source with Deno.realPathSync(from) before copying
  2. Validate the source has a real file-name component: from.split('/').pop() not in ['', '.', '..']
  3. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/745b667dc94c301e. Report an issue: GitHub.