jdx/mise · error
invalid managed directory path: {}
Error message
invalid managed directory path: {} What it means
Thrown when a managed directory path is not absolute or contains non-normal path components (like `..`, `.`, or a root/curdir component) that cannot be safely mapped into the component-by-component openat walk. The function requires a clean absolute path so each component can be opened with O_NOFOLLOW semantics. This is a strict input validation protecting the safe directory-tree builder.
Source
Thrown at src/system/managed_files.rs:1594
followed_symlinks: usize,
) -> Result<std::os::fd::OwnedFd> {
use nix::fcntl::{AtFlags, OFlag, open, openat};
use nix::sys::stat::{Mode, SFlag, fstat, fstatat, mkdirat};
if followed_symlinks > 40 {
bail!(
"too many symbolic links in managed directory {}",
path.display()
);
}
let components = path
.strip_prefix(Path::new("/"))
.wrap_err_with(|| format!("managed directory must be absolute: {}", path.display()))?
.components()
.map(|component| match component {
std::path::Component::Normal(name) => Ok(name.to_os_string()),
_ => bail!("invalid managed directory path: {}", path.display()),
})
.collect::<Result<Vec<_>>>()?;
let flags = OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW;
let mut directory = open(Path::new("/"), flags, Mode::empty())?;
let mut current = PathBuf::from("/");
for (index, name) in components.iter().enumerate() {
let component_path = current.join(name);
directory = match openat(&directory, name.as_os_str(), flags, Mode::empty()) {
Ok(directory) => directory,
Err(open_error) => {
let metadata = fstatat(&directory, name.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW);
if metadata.is_ok_and(|metadata| {
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!(View on GitHub (pinned to afd2eddd3a)
Solutions
- Convert the path to an absolute, normalized form before calling (absolutize/canonicalize, then clean `.`/`..` components)
- Fix the configured path so it is absolute and contains only normal components
- Reject or normalize user-supplied paths at your config-loading boundary
- Re-run with the corrected absolute path
Example fix
// before
open_or_create_directory_tree("opt/tools/../share")?;
// after
let path = path.absolutize()?.to_path_buf(); // yields /cwd/opt/share
open_or_create_directory_tree(&path)?; Defensive patterns
Strategy: validation
Validate before calling
fn is_clean_absolute(path: &Path) -> bool {
path.is_absolute()
&& path.strip_prefix("/").ok()
.map(|rest| rest.components().all(|c| matches!(c, std::path::Component::Normal(_))))
.unwrap_or(false)
} Type guard
fn normalize(path: &Path) -> Option<std::path::PathBuf> {
let abs = path.absolutize().ok()?.to_path_buf();
if is_clean_absolute(&abs) { Some(abs) } else { None }
} Try / catch
match result {
Err(e) if e.to_string().contains("invalid managed directory path") => {
let cleaned = absolutize_and_normalize(path)?;
retry_with(&cleaned);
}
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Normalize paths (absolutize + remove . / ..) before calling managed APIs
- Reject user-supplied relative or ..-laden paths at config boundaries
- Build paths with PathBuf::join, not string concatenation
- Store absolute paths in configuration files
When it happens
Trigger: Passing a relative path, or a path containing `..` / `.` components (e.g. `/opt/tools/../share` or `tools/share`) to the managed directory open/create API; strip_prefix("/") fails for relative paths.
Common situations: Config values built by string concatenation without normalization; user-supplied paths with `..`; paths produced by joining with environment variables that contain relative fragments; forgetting to call absolutize/canonicalize before the call.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- not a directory: {}
- managed file parent is not a directory: {}
- expected rustc output escapes its output directory
- rustc output is not a regular file: {}
- brew-cask: refusing generic artifact copy outside Homebrew p
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/e773fbecb43394a8.
Report an issue: GitHub.