{"record":{"id":"e773fbecb43394a8","repo":"jdx/mise","slug":"invalid-managed-directory-path","errorCode":null,"errorMessage":"invalid managed directory path: {}","messagePattern":"invalid managed directory path: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":1594,"sourceCode":"    followed_symlinks: usize,\n) -> Result<std::os::fd::OwnedFd> {\n    use nix::fcntl::{AtFlags, OFlag, open, openat};\n    use nix::sys::stat::{Mode, SFlag, fstat, fstatat, mkdirat};\n\n    if followed_symlinks > 40 {\n        bail!(\n            \"too many symbolic links in managed directory {}\",\n            path.display()\n        );\n    }\n\n    let components = path\n        .strip_prefix(Path::new(\"/\"))\n        .wrap_err_with(|| format!(\"managed directory must be absolute: {}\", path.display()))?\n        .components()\n        .map(|component| match component {\n            std::path::Component::Normal(name) => Ok(name.to_os_string()),\n            _ => bail!(\"invalid managed directory path: {}\", path.display()),\n        })\n        .collect::<Result<Vec<_>>>()?;\n\n    let flags = OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW;\n    let mut directory = open(Path::new(\"/\"), flags, Mode::empty())?;\n    let mut current = PathBuf::from(\"/\");\n    for (index, name) in components.iter().enumerate() {\n        let component_path = current.join(name);\n        directory = match openat(&directory, name.as_os_str(), flags, Mode::empty()) {\n            Ok(directory) => directory,\n            Err(open_error) => {\n                let metadata = fstatat(&directory, name.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW);\n                if metadata.is_ok_and(|metadata| {\n                    SFlag::from_bits_truncate(metadata.st_mode).contains(SFlag::S_IFLNK)\n                }) {\n                    let parent = fstat(&directory)?;\n                    if parent.st_uid != 0 || parent.st_mode & 0o022 != 0 {\n                        bail!(","sourceCodeStart":1576,"sourceCodeEnd":1612,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/managed_files.rs#L1576-L1612","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nopen_or_create_directory_tree(\"opt/tools/../share\")?;\n// after\nlet path = path.absolutize()?.to_path_buf(); // yields /cwd/opt/share\nopen_or_create_directory_tree(&path)?;","handlingStrategy":"validation","validationCode":"fn is_clean_absolute(path: &Path) -> bool {\n    path.is_absolute()\n        && path.strip_prefix(\"/\").ok()\n            .map(|rest| rest.components().all(|c| matches!(c, std::path::Component::Normal(_))))\n            .unwrap_or(false)\n}","typeGuard":"fn normalize(path: &Path) -> Option<std::path::PathBuf> {\n    let abs = path.absolutize().ok()?.to_path_buf();\n    if is_clean_absolute(&abs) { Some(abs) } else { None }\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"invalid managed directory path\") => {\n        let cleaned = absolutize_and_normalize(path)?;\n        retry_with(&cleaned);\n    }\n    Err(e) => return Err(e),\n    Ok(v) => v,\n}","preventionTips":["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"],"tags":["filesystem","path-validation","input-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}