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.op

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Rename the id in one config so the two entries no longer collide.
  2. Point one entry at a different target path.
  3. Make the two declarations identical if they are meant to be the same edit.
  4. 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

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/429db438ab7a5f0c. Report an issue: GitHub.