jdx/mise · error
invalid or repeated enrollment path
Error message
invalid or repeated enrollment path {} What it means
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.
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
Example fix
// before [[enrollment]] path = "/home/user/.gitconfig" [[enrollment]] path = "home/.gitconfig" // after [[enrollment]] path = "home/.gitconfig"
Defensive patterns
Strategy: validation
Validate before calling
fn path_ok(path: &str, seen: &mut std::collections::BTreeSet<String>) -> bool {
is_safe_branch_path(path)
&& (path.starts_with("home/") || path == "config" || path.starts_with("config/"))
&& seen.insert(path.to_string())
} Try / catch
match manifest.validate() {
Err(e) if e.to_string().starts_with("invalid or repeated enrollment path") => {
// rewrite/remove the offending path, then re-validate
}
other => other,
} Prevention
- Always use repo-relative paths under home/ or config/ in manifests
- Run validate() before write()/sync
- Deduplicate entries when merging manifests from multiple machines
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- app target is outside an allowed Applications directory
- dotfile enrollment metadata must be a regular file
- invalid or repeated variant for
- invalid or unenrolled permission path
- : ' ' must be a plain file name (no path separators or…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/75f15e459f51c9eb.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/manifest.rs:368
});
}
}
repo.compose(tree, &overlays)
}
pub(crate) fn validate(&self) -> Result<()> {
if self.format != 1 {
bail!("unsupported dotfile repository format {}", self.format);
}
let mut paths = std::collections::BTreeSet::new();
for entry in &self.enrollment {
if !super::sync::layout::is_safe_branch_path(&entry.path)
|| !(entry.path.starts_with("home/")
|| entry.path == "config"
|| entry.path.starts_with("config/"))
|| !paths.insert(&entry.path)
{
bail!("invalid or repeated enrollment path {}", entry.path);
}
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)
{View on GitHub (pinned to 533346cc37)