jdx/mise · error
conflicting dotfile declarations for {} first: {}
Error message
conflicting dotfile declarations for {}
first:
{}
second:
{} What it means
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.
Source
Thrown at src/system/files.rs:351
if let Some(existing) = siblings
.iter_mut()
.find(|existing| file_requests_match(config, existing, &request))
{
// the same declaration from a later layer: what it says
// about `enabled`, the policies, and the variants wins, so a
// local `enabled = false` overrides what
// it inherited instead of being dropped as a duplicate; what
// it leaves unsaid stays inherited
existing.override_from(request);
continue;
}
if let Some(existing) = siblings.iter().find(|existing| {
existing.mode != FileMode::Track
&& request.mode != FileMode::Track
&& (existing.mode != FileMode::SymlinkEach
|| request.mode != FileMode::SymlinkEach)
}) {
bail!(
"conflicting dotfile declarations for {}\n\n first:\n {}\n\n second:\n {}",
request.target.display(),
existing.origin.conflict_description(),
request.origin.conflict_description(),
);
}
siblings.push(request);
}
}
Ok(composed.into_values().flatten().collect())
}
/// Whether a declaration comes from the system or global layers (or a root
/// they compose): the only layers history enrolls files from.
pub(crate) fn declaration_is_global(config: &Config, req: &FileRequest) -> bool {
track_layer_allowed(&req.origin, &global_composed_roots(config))
}
View on GitHub (pinned to afd2eddd3a)
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.
Example fix
# before: conflicting declarations for ~/.gitconfig # global mise.toml [dotfiles."~/.gitconfig"] source = "~/dotfiles/gitconfig" # project mise.toml [dotfiles."~/.gitconfig"] content = "..." # after: single owner [dotfiles."~/.gitconfig"] source = "~/dotfiles/gitconfig"
Defensive patterns
Strategy: validation
Validate before calling
# find duplicate targets across your mise.toml files grep -h '^\[dotfiles\.' ~/.config/mise/config.toml ./mise.toml | sort | uniq -d
Prevention
- 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)
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- [dotfiles]: duplicate OCI path {path:?} as both file and dir
- [dotfiles]: duplicate OCI file path {path:?}
- conflicting dotfile edit declarations for {}/{} first:
- edits: cannot diff these entries, fix them manually: {}
- dotfile {target}: encrypt must be a boolean
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/25853c8bda4a2d4b.
Report an issue: GitHub.