jdx/mise · critical
refusing to resolve managed directory {} to the filesystem r
Error message
refusing to resolve managed directory {} to the filesystem root What it means
When a symlink in the managed path is followed, the library re-resolves the remaining path and refuses if the result is the filesystem root `/`. Resolving a managed directory to `/` would make the library operate on the root directory, which is never intended and extremely destructive. This is a hard safety invariant in the symlink-following logic.
Source
Thrown at src/system/managed_files.rs:1626
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 afd2eddd3a)
Solutions
- Remove or fix the symlink that resolves to `/` (`readlink -f <symlink>` to confirm)
- Point the symlink at a specific subdirectory rather than the root
- Recreate the managed directory structure from a clean state
- Audit symlink chains with `namei -l <path>` before relinking
Example fix
// before $ ln -s / /opt/tools/root // after $ rm /opt/tools/root $ ln -s /opt/tools-v1 /opt/tools/root
Defensive patterns
Strategy: validation
Validate before calling
fn resolves_to_root(path: &Path) -> std::io::Result<bool> {
let resolved = path.canonicalize()?;
Ok(resolved == std::path::Path::new("/"))
} Type guard
fn not_root(path: &Path) -> bool {
std::fs::canonicalize(path).map(|p| p != std::path::Path::new("/")).unwrap_or(true)
} Try / catch
match result {
Err(e) if e.to_string().contains("to the filesystem root") => {
let target = std::fs::read_link(suspect_link(path))?;
remove_and_relink(target); // never point at /
}
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Never create symlinks whose target is /
- Validate symlink targets with readlink -f before creating links
- Run namei -l on link chains to check final resolution
- Restrict who can write to directories containing managed symlinks
When it happens
Trigger: A symlink component whose target (after absolutize and appending remaining components) equals `/` — e.g. a symlink `tools -> /` or a chain of symlinks that ultimately resolves to `/`.
Common situations: A malicious or mistaken symlink pointing at `/`; careless link farms where a symlink chain (link -> link2 -> /) collapses to the root; cleanup scripts that repointed symlinks incorrectly.
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
- cannot write task stub because {} is a symbolic link
- a parent directory is now a symlink; left untouched
- too many symbolic links in managed directory {}
- global configuration directory must not be a symlink
- brew-cask: staged symlink path escaped extraction root: {}
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/646f235d128df753.
Report an issue: GitHub.