denoland/deno · error · NodeSystemError

ERR_FS_CP_NON_DIR_TO_DIR

ERR_FS_CP_NON_DIR_TO_DIR

Error message

Cannot overwrite directory with non-directory

What it means

ERR_FS_CP_NON_DIR_TO_DIR is the mirror case of DIR_TO_NON_DIR: the source is a non-directory (file, symlink to file) while the existing destination is a directory. Writing the file would clobber the directory, so fs.cp/fsp.cp rejects it via throwCpError kind 'NON_DIR_TO_DIR' with errno ENOTDIR-style code.

Source

Thrown at ext/node/polyfills/_fs/cp/cp.ts:76

  switch (err.kind) {
    case "EINVAL":
      throw new ERR_FS_CP_EINVAL({
        message: err.message,
        path: err.path,
        syscall: "cp",
        errno: EINVAL,
        code: "EINVAL",
      });
    case "DIR_TO_NON_DIR":
      throw new ERR_FS_CP_DIR_TO_NON_DIR({
        message: err.message,
        path: err.path,
        syscall: "cp",
        errno: EISDIR,
        code: "EISDIR",
      });
    case "NON_DIR_TO_DIR":
      throw new ERR_FS_CP_NON_DIR_TO_DIR({
        message: err.message,
        path: err.path,
        syscall: "cp",
        errno: ENOTDIR,
        code: "ENOTDIR",
      });
    case "EEXIST":
      throw new ERR_FS_CP_EEXIST({
        message: err.message,
        path: err.path,
        syscall: "cp",
        errno: EEXIST,
        code: "EEXIST",
      });
    case "EISDIR":
      throw new ERR_FS_EISDIR({
        message: err.message,
        path: err.path,

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Target the file inside the directory: path.join(destDir, path.basename(src))
  2. Or remove the destination directory if it should be replaced by the file
  3. Pre-stat both paths and branch on the combination (file->file, dir->dir) before copying

Example fix

// before
await fsp.cp('bundle.js', 'dist'); // dist is an existing directory

// after
await fsp.cp('bundle.js', path.join('dist', 'bundle.js'));
Defensive patterns

Strategy: validation

Validate before calling

const destStat = await fsp.lstat(dest).catch(() => null);
const target = destStat?.isDirectory() ? path.join(dest, path.basename(src)) : dest;
await fsp.cp(src, target);

Type guard

async function isDir(p) { try { return (await fsp.lstat(p)).isDirectory(); } catch { return false; } }

Try / catch

try { await fsp.cp(src, dest); } catch (e) { if (e.code === 'ERR_FS_CP_NON_DIR_TO_DIR') throw new Error(`dest ${dest} is a directory; use path.join(dest, basename(src))`); throw e; }

Prevention

When it happens

Trigger: await fsp.cp('./bundle.js', './dist') where ./dist is an existing directory; fs.cpSync('config.json', 'settings/') with settings/ a directory.

Common situations: Forgetting that a path is created as a directory by an earlier step (mkdir -p); copying a single artifact into a folder while naming the folder itself as dest instead of folder/name.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/6c7a79dd289a7a15. Report an issue: GitHub.