jdx/mise · critical · eyre::Report

refusing to resolve managed directory

Error message

refusing to resolve managed directory {} to the filesystem root

What it means

When following a symlink during managed-directory resolution, mise computes the fully resolved absolute path and refuses to continue if it lands on the filesystem root '/'. Following a chain of symlinks to '/' would make mise operate on the entire root filesystem, so it aborts instead of opening or creating directories there.

Solutions

  1. Inspect the symlink chain (readlink -f <path>) and fix the final target so it does not point at /
  2. Replace the offending symlink with a real directory
  3. Remove and recreate the managed path correctly

Example fix

// before
ln -s / ~/.local/share/mise/data  # resolves to root
// after
ln -s /data/mise ~/.local/share/mise/data
Defensive patterns

Strategy: validation

Validate before calling

import os
def resolves_to_root(p):
    return os.path.realpath(p) == "/"

Try / catch

if let Err(e) = open(path) {
    if e.to_string().contains("filesystem root") {
        // inspect readlink -f path and fix the symlink chain before retrying
    }
}

Prevention

When it happens

Trigger: A relative symlink target inside a managed path (or accumulation of resolved components via absolutize()) resolves to '/' exactly, causing open_or_create_directory_tree_inner to bail after the resolved == Path::new("/") check.

Common situations: A symlink like lib -> / or a symlink chain that walks up past the managed root; misconfigured dotfile symlinks pointing at /; recovering from a botched rm that replaced a directory with a link to /.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/646f235d128df753. Report an issue: GitHub.

Appendix: source

Thrown at src/system/managed_files.rs:1694

                    SFlag::from_bits_truncate(metadata.st_mode).contains(SFlag::S_IFLNK)
                }) {
                    let parent = fstat(&directory)?;
                    if parent.st_uid != 0 || parent.st_mode & 0o022 != 0 {
                        bail!(
                            "refusing to follow symlink {} from an untrusted parent directory",
                            component_path.display()
                        );
                    }
                    let target = nix::fcntl::readlinkat(&directory, name.as_os_str())?;
                    let mut resolved = if Path::new(&target).is_absolute() {
                        PathBuf::from(target)
                    } else {
                        current.join(target)
                    };
                    resolved.extend(components.iter().skip(index + 1));
                    let resolved = resolved.absolutize()?.to_path_buf();
                    if resolved == Path::new("/") {
                        bail!(
                            "refusing to resolve managed directory {} to the filesystem root",
                            path.display()
                        );
                    }
                    return open_or_create_directory_tree_inner(&resolved, followed_symlinks + 1);
                }
                if open_error != nix::errno::Errno::ENOENT {
                    return Err(open_error).wrap_err_with(|| {
                        format!(
                            "failed to open path component {} without following symlinks",
                            component_path.display()
                        )
                    });
                }
                let created_by_us = match mkdirat(
                    &directory,
                    name.as_os_str(),
                    Mode::from_bits_truncate(0o777),

View on GitHub (pinned to 533346cc37)