{"record":{"id":"6c7a79dd289a7a15","repo":"denoland/deno","slug":"err-fs-cp-non-dir-to-dir","errorCode":"ERR_FS_CP_NON_DIR_TO_DIR","errorMessage":"Cannot overwrite directory with non-directory","messagePattern":"Cannot overwrite directory with non-directory","errorType":"exception","errorClass":"NodeSystemError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_fs/cp/cp.ts","lineNumber":76,"sourceCode":"  switch (err.kind) {\n    case \"EINVAL\":\n      throw new ERR_FS_CP_EINVAL({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: EINVAL,\n        code: \"EINVAL\",\n      });\n    case \"DIR_TO_NON_DIR\":\n      throw new ERR_FS_CP_DIR_TO_NON_DIR({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: EISDIR,\n        code: \"EISDIR\",\n      });\n    case \"NON_DIR_TO_DIR\":\n      throw new ERR_FS_CP_NON_DIR_TO_DIR({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: ENOTDIR,\n        code: \"ENOTDIR\",\n      });\n    case \"EEXIST\":\n      throw new ERR_FS_CP_EEXIST({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: EEXIST,\n        code: \"EEXIST\",\n      });\n    case \"EISDIR\":\n      throw new ERR_FS_EISDIR({\n        message: err.message,\n        path: err.path,","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/_fs/cp/cp.ts#L58-L94","documentation":"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.","triggerScenarios":"await fsp.cp('./bundle.js', './dist') where ./dist is an existing directory; fs.cpSync('config.json', 'settings/') with settings/ a directory.","commonSituations":"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.","solutions":["Target the file inside the directory: path.join(destDir, path.basename(src))","Or remove the destination directory if it should be replaced by the file","Pre-stat both paths and branch on the combination (file->file, dir->dir) before copying"],"exampleFix":"// before\nawait fsp.cp('bundle.js', 'dist'); // dist is an existing directory\n\n// after\nawait fsp.cp('bundle.js', path.join('dist', 'bundle.js'));","handlingStrategy":"validation","validationCode":"const destStat = await fsp.lstat(dest).catch(() => null);\nconst target = destStat?.isDirectory() ? path.join(dest, path.basename(src)) : dest;\nawait fsp.cp(src, target);","typeGuard":"async function isDir(p) { try { return (await fsp.lstat(p)).isDirectory(); } catch { return false; } }","tryCatchPattern":"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; }","preventionTips":["When copying into a folder, always join(dest, basename(src))","Document whether each path variable is a file or a directory","Pre-stat both endpoints in copy utilities and branch"],"tags":["node-compat","fs","cp","copy","directory"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}