denoland/deno · error · SystemError
ERR_FS_CP_EINVAL
ERR_FS_CP_EINVAL
Error message
Invalid src or dest
What it means
fs.cp(src, dest) runs a native path check that can reject the operation with CpError::EInval (kind 'EINVAL'), which throwCpError converts into ERR_FS_CP_EINVAL (the class's default message is 'Invalid src or dest'; the actual message comes from the native check). Two conditions produce it in ext/node/ops/fs.rs: src and dest are the same file (identical dev/ino stats — 'src and dest cannot be the same'), and recursive copies where dest lies inside src ('cannot copy X to a subdirectory of self Y').
Solutions
- Resolve both paths with path.resolve and assert they differ before calling fs.cp
- Make dest a sibling, not a child: fs.cp('proj', '../proj-copy', { recursive: true })
- Use fs.realpath on both sides to catch symlink/hardlink identity, not just string equality
Example fix
// before
fs.cp('proj', 'proj/dist/backup', { recursive: true }, cb); // dest inside src
// after
fs.cp('proj', 'backup', { recursive: true }, cb); // sibling destination Defensive patterns
Strategy: try-catch
Validate before calling
const a = fs.realpathSync(src), b = fs.realpathSync(dest);
if (a === b || b.startsWith(a + path.sep)) throw new Error('cp: dest must not equal or live inside src'); Try / catch
try { await fs.promises.cp(src, dest, opts); } catch (e) { if (e.code === 'ERR_FS_CP_EINVAL') { /* fix paths, never retry unchanged */ } else throw e; } Prevention
- Always resolve both paths before copying
- Keep backup destinations outside the source tree
- Beware hardlinks: string equality is not identity — compare realpath
When it happens
Trigger: fs.cp('/a/f.txt', '/a/f.txt') or two hardlinks/symlinks resolving to the same inode; fs.cp('proj', 'proj/copy', { recursive: true }) — copying a directory into itself; a symlinked dest that resolves back to the src directory.
Common situations: Build scripts copying a directory into its own subtree (dist inside src); templating code where src and dest strings differ but resolve to the same path; hardlinked cache files used as both source and target.
Related errors
- ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY
- ERR_FS_CP_DIR_TO_NON_DIR
- ERR_FS_CP_EEXIST
- ERR_FS_CP_FIFO_PIPE
- ERR_FS_CP_NON_DIR_TO_DIR
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/fd07a4027482aece.
Report an issue: GitHub.
Appendix: source
Thrown at ext/node/polyfills/_fs/cp/cp.ts:60
IsSrcFile: 1n << 34n,
IsSrcCharDevice: 1n << 35n,
IsSrcBlockDevice: 1n << 36n,
IsSrcSymlink: 1n << 37n,
IsSrcSocket: 1n << 38n,
IsSrcFifo: 1n << 39n,
};
const {
Number,
PromiseResolve,
SymbolAsyncIterator,
} = primordials;
function throwCpError(err) {
const { EEXIST, EINVAL, EISDIR, ENOTDIR } = lazyConstants();
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,View on GitHub (pinned to 9ad36f7a2c)