jdx/mise · error
enrollment conflict in
Error message
enrollment conflict in {field}; reconcile repository metadata before syncing What it means
When merging local and remote repository enrollment metadata, `choose` picks a value only when the conflict is trivially resolvable (local==remote, remote==base, or local==base). This error means local and remote both diverged from the base for the same field, so the tool refuses to pick a winner and asks the developer to reconcile the metadata manually.
Solutions
- Edit the enrollment metadata so local and remote agree on the conflicting field, then re-run sync
- Re-fetch/reset one side: overwrite local metadata with the remote version (or vice versa) if one edit is obsolete
- Bump the base by committing the reconciled manifest so future merges resolve cleanly
- Run the repo's sync/merge in a clean state (commit or discard local metadata changes before syncing)
Example fix
// before
// local: {format:1, variants:["linux"]}, remote: {format:1, variants:["macos"]} -> bail
// after
// manually unify then sync
local.variants = ["linux", "macos"];
merge(base, local, remote)?; // resolves Defensive patterns
Strategy: validation
Validate before calling
// detect a three-way conflict before calling merge
fn conflicts<T: Clone + Eq>(base: &T, local: &T, remote: &T) -> bool {
local != remote && local != base && remote != base
} Try / catch
match enrollment.merge(base, remote) {
Err(e) if e.to_string().contains("enrollment conflict") => {
// prompt user to pick local vs remote, then re-merge
}
other => other,
} Prevention
- Commit or discard local metadata changes before syncing so merges stay two-way
- Sync metadata regularly to avoid long-lived divergent edits
- Keep one canonical device as the source of truth for enrollment metadata
When it happens
Trigger: Calling `Enrollment::merge` (via `choose`) on a manifest where the same enrollment field (e.g. `format`, a variant list, or a permission) was edited independently on two machines/sync targets since the common base.
Common situations: Two devices syncing dotfile metadata both modified the enrollment manifest and then synced; a merge/rebase was skipped and conflicting manifests were committed; an out-of-band edit landed after a fetch.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- this machine is connected to
- cannot check staged changes: git is unavailable
- cannot check staged changes in
- cannot replace local history while
- could not reuse the fetched setup preview
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/f4f9188d2239680a.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/manifest.rs:140
self.permissions.insert(portable, *bits);
}
}
self.remove_unenrolled_permissions();
Ok(())
}
/// Merge enrollment by portable path rather than JSON line positions.
/// Independent additions and policy edits commute; deletion versus a
/// policy edit remains a conflict, never an implicit reenrollment.
pub(crate) fn merge(base: &Self, local: &Self, remote: &Self) -> Result<Self> {
use std::collections::BTreeMap;
fn choose<T: Clone + Eq>(base: &T, local: &T, remote: &T, field: &str) -> Result<T> {
if local == remote || remote == base {
Ok(local.clone())
} else if local == base {
Ok(remote.clone())
} else {
bail!(
"enrollment conflict in {field}; reconcile repository metadata before syncing"
)
}
}
base.validate()?;
local.validate()?;
remote.validate()?;
if local == remote || remote == base {
return Ok(local.clone());
}
if local == base {
return Ok(remote.clone());
}
let indexed = |manifest: &Self| {
manifest
.enrollment
.iter()
.map(|entry| (entry.path.clone(), entry.clone()))View on GitHub (pinned to 533346cc37)