{"record":{"id":"73ab44503d3f6d1a","repo":"jdx/mise","slug":"refusing-to-manage-the-filesystem-root","errorCode":null,"errorMessage":"refusing to manage the filesystem root","messagePattern":"refusing to manage the filesystem root","errorType":"error_code","errorClass":"eyre::Report","httpStatus":null,"severity":"error","filePath":"src/system/managed_files.rs","lineNumber":1375,"sourceCode":"            Self::Symlink\n        } else {\n            Self::Other\n        }\n    }\n}\n\nfn absolute_target(path: &str) -> Result<PathBuf> {\n    let path = crate::file::replace_path(Path::new(path));\n    validate_privileged_target(&path)\n}\n\nfn validate_privileged_target(path: &Path) -> Result<PathBuf> {\n    if !path.is_absolute() {\n        bail!(\"managed system path must be absolute: {}\", path.display());\n    }\n    let path = path.absolutize()?.to_path_buf();\n    if path == Path::new(\"/\") {\n        bail!(\"refusing to manage the filesystem root\");\n    }\n    Ok(path)\n}\n\nfn parse_mode(mode: Option<&str>, default: u32) -> Result<u32> {\n    let Some(mode) = mode else {\n        return Ok(default);\n    };\n    let mode = mode.strip_prefix(\"0o\").unwrap_or(mode);\n    let parsed = u32::from_str_radix(mode, 8).wrap_err(\"mode must be an octal string\")?;\n    if parsed > 0o7777 {\n        bail!(\"mode must be between 0000 and 7777\");\n    }\n    Ok(parsed)\n}\n\nfn nonempty(field: &str, value: Option<String>) -> Result<Option<String>> {\n    match value {","sourceCodeStart":1357,"sourceCodeEnd":1393,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/managed_files.rs#L1357-L1393","documentation":"After absolutizing, a managed path equal to \"/\" is rejected because managing (creating, replacing, or deleting) the filesystem root is always destructive and never a legitimate declaration. `validate_privileged_target` blocks it explicitly as a safety rail.","triggerScenarios":"A [bootstrap.files]/[bootstrap.directories] entry whose path resolves to \"/\" — either literally, via a variable that expands to empty/root, or via `replace_path` substitution producing \"/\".","commonSituations":"A template variable like `${base_dir}` left unset or set to \"/\"; typo where the final path component was dropped (\"/etc/myapp/\" mishandled by tooling); experimentation gone wrong.","solutions":["Correct the path to the specific file or directory actually intended (e.g. \"/etc/myapp\").","Check any variables used in the path — one of them is expanding to \"/\" or empty; give it a real value.","If the entry is leftover scaffolding, remove it from the config entirely."],"exampleFix":"# before\n[bootstrap.directories.appdata]\npath = \"{{base_dir}}\"   # base_dir resolves to \"/\"\n\n# after\n[bootstrap.directories.appdata]\npath = \"/var/lib/myapp\"\n","handlingStrategy":"validation","validationCode":"def assert_not_root(p):\n    import os\n    r = os.path.realpath(os.path.expanduser(p))\n    if r == '/':\n        raise ValueError(f\"refusing to manage filesystem root: {p}\")\n    return r","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never let path variables default to \"/\" or empty.","Lint for path == \"/\" after variable expansion in CI.","Always include a concrete final path component in declarations."],"tags":["config","path","safety-guard","bootstrap"],"backgroundTag":"path-traversal-blocked","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}