jdx/mise · error
conflicting dotfile edit declarations for {}/{} first:
Error message
conflicting dotfile edit declarations for {}/{}
first:
{}
second:
{} What it means
Two or more mise config files declare a dotfile edit with the same target path and id but with differing definitions. edits_from_config detects the collision while composing edits and aborts, printing both conflicting origin descriptions. Identical duplicate declarations are allowed; only genuine conflicts fail.
Source
Thrown at src/system/edits.rs:172
let resolved = crate::system::files::resolve_target_arg(filter);
resolved == req.path
}
})
}
/// Aggregate edit `[dotfiles]` entries across all loaded config files. Entries
/// union global -> local, keyed by `(path, id)`; a more local config overrides
/// an edit with the same id. Malformed entries warn and are skipped.
pub(crate) fn edits_from_config(config: &Config) -> Result<Vec<EditRequest>> {
let mut composed: IndexMap<String, EditRequest> = IndexMap::new();
for config_files in config.bootstrap_config_maps() {
for request in edits_from_config_files(config_files) {
let key = format!("{}\u{0}{}", request.path.display(), request.id);
if let Some(existing) = composed.get(&key) {
if edit_requests_match(config, existing, &request) {
continue;
}
bail!(
"conflicting dotfile edit declarations for {}/{}\n\n first:\n {}\n\n second:\n {}",
request.path.display(),
request.id,
existing.origin.conflict_description(),
request.origin.conflict_description(),
);
}
composed.insert(key, request);
}
}
Ok(composed.into_values().collect())
}
/// Returns whether sibling declarations produce the same file edit.
fn edit_requests_match(config: &Config, first: &EditRequest, second: &EditRequest) -> bool {
first.path == second.path
&& first.id == second.id
&& first.op == second.opView on GitHub (pinned to afd2eddd3a)
Solutions
- Rename the id in one config so the two entries no longer collide.
- Point one entry at a different target path.
- Make the two declarations identical if they are meant to be the same edit.
- Remove the duplicate entry from the lower-priority config file.
Example fix
// project mise.toml (before, conflicts with same id in global config) [[dotfiles]] id = "zsh-alias" path = "~/.zshrc" line = "alias gs='git status'" // after [[dotfiles]] id = "zsh-alias-project" path = "~/.zshrc" line = "alias gs='git status'"
Defensive patterns
Strategy: validation
Validate before calling
# collect (path, id) pairs across all loaded config files and fail on differing duplicates
seen = {}
for cfg in config_files:
for entry in cfg.dotfiles:
key = (str(entry.path), entry.id)
if key in seen and seen[key] != entry:
raise SystemExit(f"conflicting dotfile edit for {entry.path}/{entry.id}")
seen[key] = entry Prevention
- Namespace ids per config (e.g. prefix with project name) to avoid global/project collisions.
- Avoid managing the same target file from both global and project configs.
- Run `mise edits check` in CI to catch conflicts before users hit them.
When it happens
Trigger: Two config files (e.g. global ~/.config/mise/config.toml and a project mise.toml) both define a [dotfiles] entry with the same id targeting the same file path, with different block/line/template/comment settings.
Common situations: A global config and project config both manage the same shell rc entry; copying an entry between configs and editing one copy; teams sharing a config that overlaps a personal global entry.
Related errors
- [dotfiles]: duplicate OCI file path {path:?}
- [dotfiles]: duplicate OCI path {path:?} as both file and dir
- conflicting dotfile declarations for {} first: {}
- [dotfiles]."{}": source does not exist: {}
- [dotfiles]."{}": mode symlink-each requires a directory sour
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/429db438ab7a5f0c.
Report an issue: GitHub.