denoland/deno · error
{}, symlink '{}' -> '{}'
Error message
{}, symlink '{}' -> '{}' What it means
symlink_dir() creates a directory symlink for npm package linking and rewraps any OS-level failure with this message, appending the oldpath -> newpath pair so the failing link is identifiable. The underlying error kind is preserved (or specially mapped on Windows), so the real cause — permissions, existing target, unsupported filesystem — is the inner part of the message. It is a context wrapper, not a distinct failure mode of its own.
Source
Thrown at libs/npm_installer/fs.rs:117
// esbuild's install script hardlinks its platform package's binary
// over its own JS shim) and copying in place would write through
// the link, corrupting the file at its other paths. Removing first
// also breaks hardlinks to currently-executing binaries (ETXTBSY).
let _ = sys.fs_remove_file(&new_to);
sys.fs_copy(&new_from, &new_to)?;
}
}
Ok(())
}
pub fn symlink_dir<TSys: sys_traits::BaseFsSymlinkDir>(
sys: &TSys,
oldpath: &Path,
newpath: &Path,
) -> Result<(), Error> {
let err_mapper = |err: Error, kind: Option<ErrorKind>| {
Error::new(
kind.unwrap_or_else(|| err.kind()),
format!(
"{}, symlink '{}' -> '{}'",
err,
oldpath.display(),
newpath.display()
),
)
};
sys.fs_symlink_dir(oldpath, newpath).map_err(|err| {
#[cfg(windows)]
if let Some(code) = err.raw_os_error()
&& (code as u32
== windows_sys::Win32::Foundation::ERROR_PRIVILEGE_NOT_HELD
|| code as u32
== windows_sys::Win32::Foundation::ERROR_INVALID_FUNCTION)
{View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Read the inner OS error in the message: on Windows 'Permission denied' means enabling Developer Mode (Settings > Privacy & Security > For developers) or running the terminal elevated.
- Delete the existing node_modules directory (and the specific newpath from the message if it exists) and re-run the install.
- Move node_modules to a filesystem that supports symlinks, or switch the npm install to a linker mode that copies instead of symlinking (e.g. --vendor / local node_modules with hoisted mode).
Example fix
# before (Windows, symlink privilege missing) deno install npm:chalk # ..., symlink '.../chalk' -> '.../node_modules/.deno/chalk@5.0.0/lib' # after # 1) enable Developer Mode (or run PowerShell as Administrator) # 2) clean stale links and retry rm -rf node_modules && deno install npm:chalk
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight on Windows: can we create symlinks? (cheap probe)
#[cfg(windows)]
fn symlink_privilege_ok(temp: &std::path::Path) -> bool {
let probe = temp.join("deno_symlink_probe");
let _ = std::fs::remove_file(&probe);
std::os::windows::fs::symlink_file(temp, &probe).is_ok()
&& { let _ = std::fs::remove_file(&probe); true }
} Try / catch
if let Err(err) = symlink_dir(sys, &oldpath, &newpath) {
let msg = err.to_string();
if msg.contains("symlink '") {
match err.kind() {
std::io::ErrorKind::PermissionDenied => {
// Windows: enable Developer Mode or run elevated; else fall back to copying
fallback_copy_dir(sys, &oldpath, &newpath)?;
}
std::io::ErrorKind::AlreadyExists => {
sys.fs_remove_dir_all(&newpath)?;
symlink_dir(sys, &oldpath, &newpath)?;
}
_ => return Err(err),
}
} else {
return Err(err);
}
} Prevention
- On Windows, enable Developer Mode (or run installs elevated) before any npm install that uses symlinked node_modules.
- Delete node_modules before switching linker modes or deno versions so stale targets don't collide with new symlinks.
- In containers/CI images, ensure the node_modules volume supports symlinks; prefer a local overlay/ext4 volume over bind-mounted network shares.
When it happens
Trigger: Populating node_modules with symlinked dependencies (isolated/by-symlink npm linking) when the OS symlink call fails: Windows without SeCreateSymbolicLinkPrivilege, target path already existing, or a filesystem/volume that forbids symlinks.
Common situations: Windows without Developer Mode and running unelevated; CI containers with restricted privileges; node_modules on network filesystems (NFS/SMB) or FAT/exFAT volumes; stale node_modules from a previous linker mode; Docker volume mounts that disallow symlinks.
Related errors
- On Windows the target must be a file or directory
- On Windows an `options` argument is required if the target d
- refusing to materialize package into symlinked directory
- BenchContext::end() has already been invoked
- ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/fb3d921ce892e957.
Report an issue: GitHub.