jdx/mise · error

invalid or unenrolled permission path

Error message

invalid or unenrolled permission path {path}

What it means

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.

Solutions

  1. Remove the stale permission entry or add a matching enrollment for that path
  2. Fix the permission value to be a plain mode ≤ 0o777 (e.g. 0o644, not 0o100644)
  3. Correct the permission path to exactly match the enrolled path string

Example fix

// before
[permissions]
"home/.gitconfig" = 0o100644
// after
[permissions]
"home/.gitconfig" = 0o644
Defensive patterns

Strategy: validation

Validate before calling

fn permission_ok(path: &str, bits: u32, manifest: &Manifest) -> bool {
  bits <= 0o777 && is_safe_branch_path(path) && manifest.owns_stream(path)
}

Try / catch

match manifest.validate() {
  Err(e) if e.to_string().contains("unenrolled permission path") => {
    // drop the stale permission or add the missing enrollment
  }
  other => other,
}

Prevention

When it happens

Trigger: 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`.

Common situations: 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.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/4c4e59a7d904e325. Report an issue: GitHub.

Appendix: source

Thrown at src/system/history/manifest.rs:387

            }
            let mut variants = std::collections::BTreeSet::new();
            super::select::validate(&entry.variants)?;
            for variant in &entry.variants {
                let name = variant.name();
                if name.contains('@')
                    || !super::sync::layout::is_safe_branch_path(&name)
                    || !variants.insert(name)
                {
                    bail!("invalid or repeated variant for {}", entry.path);
                }
            }
        }
        for (path, bits) in &self.permissions {
            if *bits > 0o777
                || !super::sync::layout::is_safe_branch_path(path)
                || !self.owns_stream(path)
            {
                bail!("invalid or unenrolled permission path {path}");
            }
        }
        Ok(())
    }

    pub(crate) fn read(repo: &HistoryRepo, tree: &str) -> Result<Option<Self>> {
        let Some((mode, oid)) = repo.object_at(tree, PATH)? else {
            return Ok(None);
        };
        if mode != "100644" {
            bail!("dotfile enrollment metadata must be a regular file");
        }
        let bytes = repo.cat_object_bounded(&oid, 4 * 1024 * 1024)?;
        Self::from_bytes(&bytes).map(Some)
    }

    pub(crate) fn read_gix(tree: &gix::Tree<'_>) -> Result<Option<Self>> {
        let Some(entry) = tree.lookup_entry_by_path(PATH)? else {

View on GitHub (pinned to 533346cc37)