{"record":{"id":"fb3d921ce892e957","repo":"denoland/deno","slug":"symlink","errorCode":null,"errorMessage":"{}, symlink '{}' -> '{}'","messagePattern":"(.+?), symlink '(.+?)' -> '(.+?)'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libs/npm_installer/fs.rs","lineNumber":117,"sourceCode":"      // esbuild's install script hardlinks its platform package's binary\n      // over its own JS shim) and copying in place would write through\n      // the link, corrupting the file at its other paths. Removing first\n      // also breaks hardlinks to currently-executing binaries (ETXTBSY).\n      let _ = sys.fs_remove_file(&new_to);\n      sys.fs_copy(&new_from, &new_to)?;\n    }\n  }\n\n  Ok(())\n}\n\npub fn symlink_dir<TSys: sys_traits::BaseFsSymlinkDir>(\n  sys: &TSys,\n  oldpath: &Path,\n  newpath: &Path,\n) -> Result<(), Error> {\n  let err_mapper = |err: Error, kind: Option<ErrorKind>| {\n    Error::new(\n      kind.unwrap_or_else(|| err.kind()),\n      format!(\n        \"{}, symlink '{}' -> '{}'\",\n        err,\n        oldpath.display(),\n        newpath.display()\n      ),\n    )\n  };\n\n  sys.fs_symlink_dir(oldpath, newpath).map_err(|err| {\n    #[cfg(windows)]\n    if let Some(code) = err.raw_os_error()\n      && (code as u32\n        == windows_sys::Win32::Foundation::ERROR_PRIVILEGE_NOT_HELD\n        || code as u32\n          == windows_sys::Win32::Foundation::ERROR_INVALID_FUNCTION)\n    {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/libs/npm_installer/fs.rs#L99-L135","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"# before (Windows, symlink privilege missing)\ndeno install npm:chalk   # ..., symlink '.../chalk' -> '.../node_modules/.deno/chalk@5.0.0/lib'\n\n# after\n# 1) enable Developer Mode (or run PowerShell as Administrator)\n# 2) clean stale links and retry\nrm -rf node_modules && deno install npm:chalk","handlingStrategy":"try-catch","validationCode":"// preflight on Windows: can we create symlinks? (cheap probe)\n#[cfg(windows)]\nfn symlink_privilege_ok(temp: &std::path::Path) -> bool {\n  let probe = temp.join(\"deno_symlink_probe\");\n  let _ = std::fs::remove_file(&probe);\n  std::os::windows::fs::symlink_file(temp, &probe).is_ok()\n    && { let _ = std::fs::remove_file(&probe); true }\n}","typeGuard":null,"tryCatchPattern":"if let Err(err) = symlink_dir(sys, &oldpath, &newpath) {\n  let msg = err.to_string();\n  if msg.contains(\"symlink '\") {\n    match err.kind() {\n      std::io::ErrorKind::PermissionDenied => {\n        // Windows: enable Developer Mode or run elevated; else fall back to copying\n        fallback_copy_dir(sys, &oldpath, &newpath)?;\n      }\n      std::io::ErrorKind::AlreadyExists => {\n        sys.fs_remove_dir_all(&newpath)?;\n        symlink_dir(sys, &oldpath, &newpath)?;\n      }\n      _ => return Err(err),\n    }\n  } else {\n    return Err(err);\n  }\n}","preventionTips":["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."],"tags":["npm","symlink","node-modules","windows","permissions","deno"],"backgroundTag":"symlink-creation-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}