jdx/mise · error
failed to create file symlink: {err}
Error message
failed to create file symlink: {err} What it means
On Windows 'file'-mode shim layouts, mise tries to create a file symlink for the shim; errors with kind PermissionDenied or Unsupported are treated as 'symlinks unavailable' (returns false), but any other I/O error triggers panic("failed to create file symlink: {err}"). This is a fail-fast for unexpected filesystem failures during shim installation.
Source
Thrown at src/shims.rs:2813
{
std::os::unix::fs::symlink(target, link)
}
#[cfg(windows)]
{
std::os::windows::fs::symlink_file(target, link)
}
};
match result {
Ok(()) => true,
Err(err)
if matches!(
err.kind(),
std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::Unsupported
) =>
{
false
}
Err(err) => panic!("failed to create file symlink: {err}"),
}
}
/// A single-link mise layout: the PATH-visible `mise.exe` is a link, and
/// `mise-shim.exe` ships only beside the real binary. Returns the linked
/// mise and the real shim, or `None` when symlinks cannot be created on
/// this host.
fn single_link_layout(temp: &Path) -> Option<(PathBuf, PathBuf)> {
let real_dir = temp.join("real").join("bin");
let links_dir = temp.join("links");
fs::create_dir_all(&real_dir).unwrap();
fs::create_dir_all(&links_dir).unwrap();
let real_mise = real_dir.join("mise.exe");
fs::write(&real_mise, "mise").unwrap();
let real_shim = real_dir.join("mise-shim.exe");
fs::write(&real_shim, "mise-shim").unwrap();
let linked_mise = links_dir.join("mise.exe");
if !try_symlink_file(&real_mise, &linked_mise) {View on GitHub (pinned to afd2eddd3a)
Solutions
- Recreate the mise shim directory and run `mise reshim`
- Check the underlying io error in the message and fix the specific cause (missing directory, invalid path, long path)
- Enable Windows long-path support or shorten the install path if the error is path-length related
- If symlinks are fundamentally unavailable in your environment, switch MISE_WINDOWS_SHIM_MODE to a supported mode instead of symlink mode
Defensive patterns
Strategy: try-catch
Validate before calling
// Before relying on file symlinks on Windows, probe once:
let probe = dir.join(".mise_symlink_probe");
let symlinks_ok = std::os::windows::fs::symlink_file(std::env::current_exe().unwrap(), &probe).is_ok();
let _ = std::fs::remove_file(&probe); Try / catch
match std::os::windows::fs::symlink_file(&target, &link) {
Ok(()) => { /* proceed */ }
Err(e) if matches!(e.kind(), io::ErrorKind::PermissionDenied | io::ErrorKind::Unsupported) => { /* fall back to copy */ }
Err(e) => { /* treat all other errors as symlink-unavailable and fall back too */ }
} Prevention
- Ensure the shim directory exists and is on a local NTFS volume before creating shims
- Enable Windows Developer Mode or run elevated if symlink privileges are missing
- Keep mise install paths short to avoid MAX_PATH issues
- Fall back to copy-based shim mode when symlinks are unavailable
When it happens
Trigger: std::os::windows::fs::symlink_file fails with an error other than PermissionDenied/Unsupported — e.g. the target directory does not exist, the path is invalid, or an antivirus/filesystem filter returns an exotic error — while creating shim links in single-link mise layouts.
Common situations: Shim directory removed or on a network/UNC drive mid-run; path too long (>260 chars) on Windows; shim target path occupied by a locked file; exotic filesystem (FAT/exFAT, Docker bind mount) that fails symlinks with unusual error kinds.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- rustc output is not a regular file: {}
- Unknown shim mode
- {other:?}
- expected world-writable ancestor to be refused
- expected symlinked appdir tail to be rejected
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/bbfb5e5a05d1d822.
Report an issue: GitHub.