denoland/deno · error · ERR_FS_CP_SOCKET
EINVAL
EINVAL
Error message
cannot copy a socket file: ${dest} What it means
Thrown by the JS slow path of Deno's cp polyfill when a copied entry is a unix-domain socket: 'cannot copy a socket file: <dest>' with code EINVAL (cp.ts:204-211). It fires during recursive copies whose options (filter, dereference, force: false, errorOnExist, preserveTimestamps, verbatimSymlinks, nonzero mode) disable the native fast path — see canUseNativeFastPath at cp.ts:168-176. The Rust fast path raises the equivalent ERR_FS_CP_SOCKET instead.
Source
Thrown at ext/node/polyfills/_fs/cp/cp.ts:210
errno: EISDIR,
code: "EISDIR",
});
} else if (
(statInfo & CpEntryFlags.IsSrcFile) ||
(statInfo & CpEntryFlags.IsSrcCharDevice) ||
(statInfo & CpEntryFlags.IsSrcBlockDevice)
) {
return onFile(statInfo, src, dest, opts);
} else if (statInfo & CpEntryFlags.IsSrcSymlink) {
const isDestExists = !!(statInfo & CpEntryFlags.IsDestExists);
return onLink(isDestExists, src, dest, opts);
} else if (statInfo & CpEntryFlags.IsSrcSocket) {
throw new ERR_FS_CP_SOCKET({
message: `cannot copy a socket file: ${dest}`,
path: dest,
syscall: "cp",
errno: EINVAL,
code: "EINVAL",
});
} else if (statInfo & CpEntryFlags.IsSrcFifo) {
throw new ERR_FS_CP_FIFO_PIPE({
message: `cannot copy a FIFO pipe: ${dest}`,
path: dest,
syscall: "cp",
errno: EINVAL,
code: "EINVAL",
});
}
throw new ERR_FS_CP_UNKNOWN({
message: `cannot copy an unknown file type: ${dest}`,
path: dest,
syscall: "cp",
errno: EINVAL,
code: "EINVAL",
});
}View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Extend your filter to skip sockets: inside filter, return false when (await lstat(src)).isSocket().
- Name-based guard as a cheap alternative: filter: (s) => !s.endsWith('.sock').
- Scope the copy to the data subdirectory instead of the runtime root that holds sockets.
Example fix
// before
await fs.promises.cp('/tmp/app', '/backup/app', {
recursive: true,
filter: (s) => !s.includes('cache'),
});
// EINVAL: cannot copy a socket file: /backup/app/run.sock
// after
await fs.promises.cp('/tmp/app', '/backup/app', {
recursive: true,
filter: async (s, d) =>
!s.includes('cache') && !(await fs.promises.lstat(s)).isSocket(),
}); Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs';
await fs.promises.cp(srcDir, destDir, {
recursive: true,
filter: async (p) => {
const st = await fs.promises.lstat(p);
return !st.isSocket() && !st.isFIFO();
},
}); Try / catch
try {
await fs.promises.cp(a, b, { recursive: true, dereference: true });
} catch (err) {
if (err.code === 'EINVAL' && /cannot copy a socket file/.test(err.message)) {
// rerun with a socket-skipping filter
} else throw err;
} Prevention
- When you already pass a filter, extend it to reject sockets instead of only selecting files
- Keep runtime sockets in a dedicated subdir and exclude that dir from copies
- Check err.code === 'EINVAL' with syscall 'cp' — this throw path uses raw EINVAL, not ERR_FS_CP_SOCKET
When it happens
Trigger: fs.cp('/tmp', backup, { recursive: true, dereference: true }) walking into .X11-unix sockets; recursive filtered copies of runtime dirs containing docker.sock or an app's listening socket.
Common situations: Dev tooling that backs up project tmp/ dirs (Rails tmp/sockets/puma.sock); sandbox copies that include X11 or dbus sockets; docker-in-docker scripts copying /var/run.
Related errors
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/343051f047aa1c4c.
Report an issue: GitHub.