{"record":{"id":"75f15e459f51c9eb","repo":"jdx/mise","slug":"invalid-or-repeated-enrollment-path","errorCode":null,"errorMessage":"invalid or repeated enrollment path {}","messagePattern":"invalid or repeated enrollment path (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/manifest.rs","lineNumber":368,"sourceCode":"                });\n            }\n        }\n        repo.compose(tree, &overlays)\n    }\n\n    pub(crate) fn validate(&self) -> Result<()> {\n        if self.format != 1 {\n            bail!(\"unsupported dotfile repository format {}\", self.format);\n        }\n        let mut paths = std::collections::BTreeSet::new();\n        for entry in &self.enrollment {\n            if !super::sync::layout::is_safe_branch_path(&entry.path)\n                || !(entry.path.starts_with(\"home/\")\n                    || entry.path == \"config\"\n                    || entry.path.starts_with(\"config/\"))\n                || !paths.insert(&entry.path)\n            {\n                bail!(\"invalid or repeated enrollment path {}\", entry.path);\n            }\n            let mut variants = std::collections::BTreeSet::new();\n            super::select::validate(&entry.variants)?;\n            for variant in &entry.variants {\n                let name = variant.name();\n                if name.contains('@')\n                    || !super::sync::layout::is_safe_branch_path(&name)\n                    || !variants.insert(name)\n                {\n                    bail!(\"invalid or repeated variant for {}\", entry.path);\n                }\n            }\n        }\n        for (path, bits) in &self.permissions {\n            if *bits > 0o777\n                || !super::sync::layout::is_safe_branch_path(path)\n                || !self.owns_stream(path)\n            {","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/manifest.rs#L350-L386","documentation":"Every enrollment path must be a safe branch path (per `layout::is_safe_branch_path`), must live under `home/` or be `config`/under `config/`, and must appear at most once. `validate` bails when any of these fails, preventing path traversal or duplicate enrollments in the repository branch layout.","triggerScenarios":"Calling `validate` (via `tracking`, `write`, or permission capture) with a manifest containing an enrollment path that escapes the allowed layout (e.g. `../secrets`, absolute paths, `..` segments), lives outside `home/`/`config`, or is listed twice.","commonSituations":"Hand-editing the manifest and adding an absolute or relative path outside the allowed roots; a copy/paste duplicating an entry; migrating manifests from another dotfile manager with different path conventions.","solutions":["Rewrite the path to be relative and inside `home/` or `config/` (e.g. `home/.gitconfig`, `config/foo/bar`)","Remove duplicate enrollment entries so each path appears once","Replace any `..` segments or absolute paths with the canonical relative branch path","Run the tool's manifest validation before writing to catch this early"],"exampleFix":"// before\n[[enrollment]]\npath = \"/home/user/.gitconfig\"\n[[enrollment]]\npath = \"home/.gitconfig\"\n// after\n[[enrollment]]\npath = \"home/.gitconfig\"","handlingStrategy":"validation","validationCode":"fn path_ok(path: &str, seen: &mut std::collections::BTreeSet<String>) -> bool {\n  is_safe_branch_path(path)\n    && (path.starts_with(\"home/\") || path == \"config\" || path.starts_with(\"config/\"))\n    && seen.insert(path.to_string())\n}","typeGuard":null,"tryCatchPattern":"match manifest.validate() {\n  Err(e) if e.to_string().starts_with(\"invalid or repeated enrollment path\") => {\n    // rewrite/remove the offending path, then re-validate\n  }\n  other => other,\n}","preventionTips":["Always use repo-relative paths under home/ or config/ in manifests","Run validate() before write()/sync","Deduplicate entries when merging manifests from multiple machines"],"tags":["manifest","validation","path-safety","duplicates"],"backgroundTag":"invalid-argument-value","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"}