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

  1. Recreate the mise shim directory and run `mise reshim`
  2. Check the underlying io error in the message and fix the specific cause (missing directory, invalid path, long path)
  3. Enable Windows long-path support or shorten the install path if the error is path-length related
  4. 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

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/bbfb5e5a05d1d822. Report an issue: GitHub.