{"record":{"id":"4c4e59a7d904e325","repo":"jdx/mise","slug":"invalid-or-unenrolled-permission-path-path","errorCode":null,"errorMessage":"invalid or unenrolled permission path {path}","messagePattern":"invalid or unenrolled permission path (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/manifest.rs","lineNumber":387,"sourceCode":"            }\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            {\n                bail!(\"invalid or unenrolled permission path {path}\");\n            }\n        }\n        Ok(())\n    }\n\n    pub(crate) fn read(repo: &HistoryRepo, tree: &str) -> Result<Option<Self>> {\n        let Some((mode, oid)) = repo.object_at(tree, PATH)? else {\n            return Ok(None);\n        };\n        if mode != \"100644\" {\n            bail!(\"dotfile enrollment metadata must be a regular file\");\n        }\n        let bytes = repo.cat_object_bounded(&oid, 4 * 1024 * 1024)?;\n        Self::from_bytes(&bytes).map(Some)\n    }\n\n    pub(crate) fn read_gix(tree: &gix::Tree<'_>) -> Result<Option<Self>> {\n        let Some(entry) = tree.lookup_entry_by_path(PATH)? else {","sourceCodeStart":369,"sourceCodeEnd":405,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/manifest.rs#L369-L405","documentation":"Permissions can only be recorded for paths that are enrolled in the manifest. `validate` rejects a permission entry whose bits exceed 0o777, whose path is not a safe branch path, or which no enrollment (`owns_stream`) covers — ensuring the permission map stays consistent with enrolled streams.","triggerScenarios":"Calling `validate` (via `tracking`, `write`, or permission capture) with a `[permissions]` entry pointing at a path never listed under `enrollment`, a permission value above 0o777 (e.g. 0o100644-style file-mode values pasted in), or a path failing `is_safe_branch_path`.","commonSituations":"Removing an enrollment but leaving its permission entry behind; setting permissions to full file modes like 0o644 with extra high bits (e.g. 0o100644); typos in the permission path so it no longer matches any enrollment.","solutions":["Remove the stale permission entry or add a matching enrollment for that path","Fix the permission value to be a plain mode ≤ 0o777 (e.g. 0o644, not 0o100644)","Correct the permission path to exactly match the enrolled path string"],"exampleFix":"// before\n[permissions]\n\"home/.gitconfig\" = 0o100644\n// after\n[permissions]\n\"home/.gitconfig\" = 0o644","handlingStrategy":"validation","validationCode":"fn permission_ok(path: &str, bits: u32, manifest: &Manifest) -> bool {\n  bits <= 0o777 && is_safe_branch_path(path) && manifest.owns_stream(path)\n}","typeGuard":null,"tryCatchPattern":"match manifest.validate() {\n  Err(e) if e.to_string().contains(\"unenrolled permission path\") => {\n    // drop the stale permission or add the missing enrollment\n  }\n  other => other,\n}","preventionTips":["When removing an enrollment, remove its permissions entry too","Store plain permission bits (≤ 0o777), never full file-mode values like 0o100644","Keep permission paths exactly equal to enrolled path strings"],"tags":["manifest","validation","permissions","consistency"],"backgroundTag":"invalid-config-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"}