{"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":"SystemError","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/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/_fs/cp/cp.ts#L106-L142","documentation":"When fs.cp processes a symlink whose resolution would make dest a subdirectory of src (specifically, resolved dest lies inside resolved src), the native guard rejects with CpError::SymlinkToSubdirectory (kind 'SYMLINK_TO_SUBDIRECTORY'), mapped by throwCpError to ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY ('Cannot overwrite symlink in subdirectory of self', errno EINVAL). The guard exists because unlinking/overwriting such a dest would delete the source's own contents or leave a broken symlink loop — recursive copies must not destroy their input.","triggerScenarios":"fs.cp('proj', 'proj/dist/vendor/proj-link', { recursive: true }) where the dest chain passes through a symlink back into proj; symlink farms (node_modules symlinking packages into the tree being copied) where the copy target resolves inside the copy source; tooling that copies a monorepo into one of its own packages' build outputs.","commonSituations":"pnpm-style symlink layouts being recursively copied; bundlers writing into a path that symlinks back to the source tree; CI artifact steps that copy the workspace into workspace/target/ while target contains symlinks to sources.","solutions":["Copy to a destination outside the source tree entirely (sibling or temp dir, then move)","Break the self-referential symlink chain: resolve dest with fs.realpath and reject paths that start with the resolved src prefix","Use verbatimSymlinks where appropriate so symlinks are recreated as-is instead of being followed into the source tree"],"exampleFix":"// before\nfs.cp('proj', 'proj/dist/backup', { recursive: true }, cb); // resolves into self\n\n// after\nfs.cp('proj', fs.mkdtempSync('/tmp/copy-'), { recursive: true }, cb); // outside src","handlingStrategy":"try-catch","validationCode":"const s = fs.realpathSync(src), d = fs.realpathSync(dest);\nif (d === s || d.startsWith(s + path.sep)) throw new Error('cp: dest resolves inside src');","typeGuard":null,"tryCatchPattern":"try { await fs.promises.cp(src, dest, { recursive: true }); } catch (e) { if (e.code === 'ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY') { /* choose a dest outside the src tree and rerun */ } else throw e; }","preventionTips":["Copy to destinations outside the source tree, then move","With pnpm-style symlink layouts, copy with verbatimSymlinks or tar first","Check resolved (realpath) containment, not raw string prefixes"],"tags":["node-compat","fs","cp","copy","symlink","err-fs-cp-symlink-to-subdirectory","einval","deno"],"backgroundTag":"fs-copy-into-itself","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}