{"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":351,"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":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/files.rs#L333-L369","documentation":"When composing FileRequests from [dotfiles] config, composed_files_from_config detects two declarations for the same target whose modes conflict. Two non-Track declarations for the same destination are incompatible unless both are SymlinkEach (which composes disjoint leaves); anything else — e.g. Track+Copy, Copy+Symlink, SymlinkOnce+SymlinkEach — bails with both declarations' origin descriptions.","triggerScenarios":"Calling files_from_config → composed_files_from_config with two [dotfiles] entries resolving to the same target path where at least one is not Track and not both SymlinkEach (e.g. one config file declares a symlink, another declares copy/track for the same destination).","commonSituations":"The same dotfile path is declared in global config and a project config with different modes (one uses source symlink, another inline content/template/copy); merging the layered configs produces two conflicting declarations for one target.","solutions":["Make the two declarations agree: use the same mode (e.g. both SymlinkEach) or merge them into a single entry in one config file.","Change one declaration to mode Track, which observes the file without owning an apply footprint and thus composes with other modes.","Delete the redundant declaration so only one non-Track owner remains for that target."],"exampleFix":"# before: conflicting declarations for ~/.gitconfig\n# global mise.toml\n[dotfiles.\"~/.gitconfig\"]\nsource = \"~/dotfiles/gitconfig\"\n# project mise.toml\n[dotfiles.\"~/.gitconfig\"]\ncontent = \"...\"\n\n# after: single owner\n[dotfiles.\"~/.gitconfig\"]\nsource = \"~/dotfiles/gitconfig\"","handlingStrategy":"validation","validationCode":"# find duplicate targets across your mise.toml files\ngrep -h '^\\[dotfiles\\.' ~/.config/mise/config.toml ./mise.toml | sort | uniq -d","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Declare each dotfile target in exactly one config layer","Use Track mode for read-only observation that composes with other declarations","Keep symlink modes consistent (SymlinkEach on both sides if splitting)"],"tags":["rust","dotfiles","config","conflict"],"backgroundTag":"conflicting-config-options","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}