{"record":{"id":"25853c8bda4a2d4b","repo":"jdx/mise","slug":"conflicting-dotfile-declarations-for-first","errorCode":null,"errorMessage":"conflicting dotfile declarations for {}\n\n  first:\n    {}\n\n  second:\n    {}","messagePattern":"conflicting dotfile declarations for (.+?)\n\n  first:\n    (.+?)\n\n  second:\n    (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/files.rs","lineNumber":455,"sourceCode":"            if let Some(existing) = siblings\n                .iter_mut()\n                .find(|existing| file_requests_match(config, existing, &request))\n            {\n                // the same declaration from a later layer: what it says\n                // about `enabled`, the policies, and the variants wins, so a\n                // local `enabled = false` overrides what\n                // it inherited instead of being dropped as a duplicate; what\n                // it leaves unsaid stays inherited\n                existing.override_from(request);\n                continue;\n            }\n            if let Some(existing) = siblings.iter().find(|existing| {\n                existing.mode != FileMode::Track\n                    && request.mode != FileMode::Track\n                    && (existing.mode != FileMode::SymlinkEach\n                        || request.mode != FileMode::SymlinkEach)\n            }) {\n                bail!(\n                    \"conflicting dotfile declarations for {}\\n\\n  first:\\n    {}\\n\\n  second:\\n    {}\",\n                    request.target.display(),\n                    existing.origin.conflict_description(),\n                    request.origin.conflict_description(),\n                );\n            }\n            siblings.push(request);\n        }\n    }\n    Ok(composed.into_values().flatten().collect())\n}\n\n/// Whether a declaration comes from the system or global layers (or a root\n/// they compose): the only layers history enrolls files from.\npub(crate) fn declaration_is_global(config: &Config, req: &FileRequest) -> bool {\n    track_layer_allowed(&req.origin, &global_composed_roots(config))\n}\n","sourceCodeStart":437,"sourceCodeEnd":473,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/files.rs#L437-L473","documentation":"`composed_files_from_config` detects two `[dotfiles]` declarations that would manage the same destination target. If both are in owning (non-Track) modes and they are not both `symlink_each`, the library cannot decide which declaration owns the destination and bails with a message describing both origins.","triggerScenarios":"Two entries in `[dotfiles]` (possibly across layered config files) resolve to the same absolute destination, e.g. `\"~/.gitconfig\" = \"a/gitconfig\"` and `\"~/.gitconfig\" = { source = \"b/gitconfig\" }`, where neither is `mode = \"track\"` and not both are `symlink_each`.","commonSituations":"Merging dotfile configs from team and personal files that both ship the same rc file; refactoring keys and leaving a duplicate behind; an included config re-declaring an entry already present globally.","solutions":["Remove or rename one of the conflicting declarations so each target is declared once","Set both conflicting entries to `mode = \"track\"` or both to `mode = \"symlink_each\"` if that matches intent (these combinations are allowed)","Move one declaration to a different destination path"],"exampleFix":"// before\n\"~/.gitconfig\" = \"dotfiles/gitconfig\"\n\"~/.gitconfig\" = { source = \"work/gitconfig\" }\n// after\n\"~/.gitconfig\" = \"dotfiles/gitconfig\"   # single owner","handlingStrategy":"validation","validationCode":"function findDuplicateTargets(entries) {\n  const seen = new Map(); const dupes = [];\n  for (const [target, e] of Object.entries(entries)) {\n    if (seen.has(target)) dupes.push(target); else seen.set(target, e);\n  }\n  return dupes;\n}","typeGuard":null,"tryCatchPattern":"try { applyFiles(config); } catch (e) {\n  if (String(e.message).startsWith('conflicting dotfile declarations for')) {\n    // parse target from message, dedupe declarations for that target\n  } else throw e;\n}","preventionTips":["Keep one declaration per destination across all config layers","When layering team + personal dotfile configs, audit for overlapping targets","Use `mode = \"track\"` (or `symlink_each` on both) only when shared ownership is intentional"],"tags":["config","dotfiles","conflict"],"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"}