{"record":{"id":"afadfc2198643b75","repo":"denoland/deno","slug":"err-fs-cp-symlink-to-subdirectory","errorCode":"ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY","errorMessage":"Cannot overwrite symlink in subdirectory of self","messagePattern":"Cannot overwrite symlink in subdirectory of self","errorType":"exception","errorClass":"NodeSystemError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/_fs/cp/cp.ts","lineNumber":124,"sourceCode":"      });\n    case \"FIFO\":\n      throw new ERR_FS_CP_FIFO_PIPE({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: EINVAL,\n        code: \"EINVAL\",\n      });\n    case \"UNKNOWN\":\n      throw new ERR_FS_CP_UNKNOWN({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: EINVAL,\n        code: \"EINVAL\",\n      });\n    case \"SYMLINK_TO_SUBDIRECTORY\":\n      throw new ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY({\n        message: err.message,\n        path: err.path,\n        syscall: \"cp\",\n        errno: EINVAL,\n        code: \"EINVAL\",\n      });\n    default:\n      throw err;\n  }\n}\n\nasync function cpFn(\n  src,\n  dest,\n  opts,\n) {\n  try {\n    if (canUseNativeFastPath(opts)) {","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/denoland/deno/blob/89f33cbef296a2b287f323d42de54c871fa69c77/ext/node/polyfills/_fs/cp/cp.ts#L106-L142","documentation":"ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY ('Cannot overwrite symlink in subdirectory of self') is thrown for kind 'SYMLINK_TO_SUBDIRECTORY': with dereference:true, the resolved destination lands inside the source tree (dest is a subdirectory of src), so continuing would make cp copy a directory into itself. It is the same guard Node uses to prevent infinite recursive copies.","triggerScenarios":"await fsp.cp('/data/project', '/data/project/sub/copy', { recursive: true, dereference: true }); copying a folder into a nested folder of itself; build tools writing output into an input subfolder while following symlinks.","commonSituations":"Out-of-tree output paths misconfigured to live under the source tree; monorepo scripts whose dest is computed relative to src and ends up nested.","solutions":["Choose a destination outside the source tree","Or set dereference:false / verbatimSymlinks as appropriate so dest resolution does not fold into src","Guard with path.relative: if the result doesn't start with '..' and isn't '', dest is inside src — reject before copying"],"exampleFix":"// before\nawait fsp.cp(src, path.join(src, 'dist/backup'), { recursive: true, dereference: true });\n\n// after\nconst dest = path.join(rootOutsideSrc, 'backup');\nawait fsp.cp(src, dest, { recursive: true, dereference: true });","handlingStrategy":"validation","validationCode":"const rel = path.relative(path.resolve(src), path.resolve(dest));\nconst destInsideSrc = rel !== '' && !rel.startsWith('..');\nif (destInsideSrc) throw new Error('dest must not be inside src when dereference is enabled');","typeGuard":"function isDestInsideSrc(src, dest) {\n  const rel = path.relative(path.resolve(src), path.resolve(dest));\n  return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);\n}","tryCatchPattern":"try { await fsp.cp(src, dest, { recursive: true, dereference: true }); } catch (e) { if (e.code === 'ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY') throw new Error(`dest ${dest} is inside src ${src}`); throw e; }","preventionTips":["Place outputs outside the source tree","Check path.relative(src, dest) before recursive copies with dereference","Prefer dereference:false when you only need to preserve symlinks"],"tags":["node-compat","fs","cp","symlink","recursion","dereference"],"backgroundTag":null,"analyzedSha":"89f33cbef296a2b287f323d42de54c871fa69c77","analyzedAt":"2026-08-16T07:54:21.310Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}