{"record":{"id":"f4f9188d2239680a","repo":"jdx/mise","slug":"enrollment-conflict-in-field-reconcile-reposito","errorCode":null,"errorMessage":"enrollment conflict in {field}; reconcile repository metadata before syncing","messagePattern":"enrollment conflict in (.+?); reconcile repository metadata before syncing","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/manifest.rs","lineNumber":140,"sourceCode":"                self.permissions.insert(portable, *bits);\n            }\n        }\n        self.remove_unenrolled_permissions();\n        Ok(())\n    }\n\n    /// Merge enrollment by portable path rather than JSON line positions.\n    /// Independent additions and policy edits commute; deletion versus a\n    /// policy edit remains a conflict, never an implicit reenrollment.\n    pub(crate) fn merge(base: &Self, local: &Self, remote: &Self) -> Result<Self> {\n        use std::collections::BTreeMap;\n        fn choose<T: Clone + Eq>(base: &T, local: &T, remote: &T, field: &str) -> Result<T> {\n            if local == remote || remote == base {\n                Ok(local.clone())\n            } else if local == base {\n                Ok(remote.clone())\n            } else {\n                bail!(\n                    \"enrollment conflict in {field}; reconcile repository metadata before syncing\"\n                )\n            }\n        }\n        base.validate()?;\n        local.validate()?;\n        remote.validate()?;\n        if local == remote || remote == base {\n            return Ok(local.clone());\n        }\n        if local == base {\n            return Ok(remote.clone());\n        }\n        let indexed = |manifest: &Self| {\n            manifest\n                .enrollment\n                .iter()\n                .map(|entry| (entry.path.clone(), entry.clone()))","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/manifest.rs#L122-L158","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\n// local: {format:1, variants:[\"linux\"]}, remote: {format:1, variants:[\"macos\"]} -> bail\n// after\n// manually unify then sync\nlocal.variants = [\"linux\", \"macos\"];\nmerge(base, local, remote)?; // resolves","handlingStrategy":"validation","validationCode":"// detect a three-way conflict before calling merge\nfn conflicts<T: Clone + Eq>(base: &T, local: &T, remote: &T) -> bool {\n  local != remote && local != base && remote != base\n}","typeGuard":null,"tryCatchPattern":"match enrollment.merge(base, remote) {\n  Err(e) if e.to_string().contains(\"enrollment conflict\") => {\n    // prompt user to pick local vs remote, then re-merge\n  }\n  other => other,\n}","preventionTips":["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"],"tags":["merge-conflict","sync","git","state"],"backgroundTag":"conflicting-config-options","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"}