jdx/mise · error
invalid or repeated variant for {}
Error message
invalid or repeated variant for {} What it means
During dotfile enrollment manifest validation, each variant name must be safe and unique. This error fires when a variant name contains '@', is not a safe branch path per sync::layout::is_safe_branch_path, or duplicates a variant already seen for the same entry. It prevents ambiguous or unportable stream names from being persisted.
Source
Thrown at src/system/history/manifest.rs:378
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)
{
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);
};View on GitHub (pinned to afd2eddd3a)
Solutions
- Remove duplicate variant entries for the affected path, keeping one.
- Remove '@' from the variant name; '@' is reserved syntax.
- Rename the variant to satisfy is_safe_branch_path (relative, no traversal, safe characters).
- Regenerate the manifest with the enrollment tooling instead of hand-editing.
Example fix
// before (manifest JSON)
{"path": "dotfiles/zshrc", "variants": ["main", "main"]}
// after
{"path": "dotfiles/zshrc", "variants": ["main", "laptop"]} Defensive patterns
Strategy: validation
Validate before calling
fn variant_ok(name: &str, seen: &mut std::collections::HashSet<&str>) -> bool {
!name.contains('@') && seen.insert(name)
} Type guard
fn is_safe_variant(name: &str) -> bool { !name.contains('@') && !name.contains("..") && !name.starts_with('/') } Try / catch
match manifest.validate() {
Err(e) if e.to_string().starts_with("invalid or repeated variant") => {
eprintln!("fix manifest variants: {e}");
}
r => r?,
} Prevention
- Generate manifests via the enrollment tooling, never by hand.
- Keep variant names free of '@' and path-unsafe characters.
- Deduplicate variants per path before writing.
When it happens
Trigger: Calling Manifest::validate (directly or via read/write/tracking) on a manifest whose entry.variants contains a name with '@', an unsafe path (e.g. '..', absolute, reserved components), or the same variant name twice for one entry.path.
Common situations: Hand-edited or tool-generated enrollment manifests with duplicate variants; names copied from refs like 'origin/main@1'; paths with traversal components or characters rejected by is_safe_branch_path.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- dotfile enrollment metadata must be a regular file
- [dotfiles]."{}": manifest requires the source to be a direct
- invalid or unenrolled permission path {path}
- the packslip names an executable {:?}, which is not a plain
- {} exists but is not a git checkout with an origin remote
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/4a237cdd70d0ce5c.
Report an issue: GitHub.