jdx/mise · error

existing file conflicts with adoption: {entry}

Error message

existing file conflicts with adoption: {entry}

What it means

During adoption of a non-empty destination (no `.git`), install_at compares each transferred file with any existing file at the same relative path. Adoption only proceeds when the existing file is a regular file with byte-identical content and the transferred entry is not itself a symlink; anything else — differing content, a directory in the way, or a symlink on either side — aborts the adoption. This guarantees adoption never overwrites or clobbers user data.

Source

Thrown at src/system/remote_repository.rs:338

        return Ok(destination.to_path_buf());
    }
    let nonempty = destination.exists() && destination.read_dir()?.next().is_some();
    if nonempty {
        for entry in entries.split('\0').filter(|s| !s.is_empty()) {
            let mut ancestor = destination.to_path_buf();
            for component in Path::new(entry).components() {
                ancestor.push(component);
                if ancestor.is_symlink() {
                    bail!("existing symbolic link conflicts with adoption: {entry}");
                }
            }
            let existing = destination.join(entry);
            if existing.exists()
                && (checkout.join(entry).is_symlink()
                    || !existing.is_file()
                    || std::fs::read(&existing)? != std::fs::read(checkout.join(entry))?)
            {
                bail!("existing file conflicts with adoption: {entry}");
            }
        }
        if dry_run {
            let new_files = entries
                .split('\0')
                .filter(|s| !s.is_empty())
                .filter(|entry| !destination.join(entry).exists())
                .count();
            miseprintln!(
                "Would adopt {shown} as the global configuration repository ({new_files} new file(s); existing files and local overrides preserved)"
            );
            return Ok(destination.to_path_buf());
        }
        eprintln!(
            "Adopt existing global configuration at {} (preserving existing files and local overrides)",
            destination.display()
        );
        if !yes

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Diff the conflicting files (`diff <destination>/<entry> <source-repo>/<entry>`) and reconcile them in the source repository, then re-transfer.
  2. If the local version should win, copy it into the source repo, commit, and regenerate the bundle so contents match.
  3. If the transferred version should win, back up and remove the differing local file before retrying.
  4. Remove unrelated stale files/directories that occupy transferred entry paths (e.g. leftover directories where the transfer expects a file).

Example fix

// before: existing config.toml differs from transferred one
diff ~/.config/mise/config.toml ./source/config.toml
# reconcile edits in the source repo, commit, then:
cp ./source/config.toml ~/.config/mise/config.toml
// after: files are byte-identical; adoption succeeds
Defensive patterns

Strategy: validation

Validate before calling

const { execFileSync } = require('child_process');
const entries = execFileSync('git', ['-C', checkout, 'ls-tree', '-r', '--name-only', 'HEAD']).toString().split('\n');
for (const e of entries.filter(Boolean)) {
  const existing = path.join(dest, e);
  if (fs.existsSync(existing) && !fs.statSync(existing).isFile()) throw new Error(`conflict at ${e}`);
  if (fs.existsSync(existing) && !fs.readFileSync(existing).equals(fs.readFileSync(path.join(checkout, e)))) throw new Error(`content differs at ${e}`);
}

Prevention

When it happens

Trigger: Installing into an existing non-empty directory where `destination/<entry>` already exists and differs from the checkout's version: different bytes, existing path is a directory, or the transferred (or existing) entry is a symlink.

Common situations: User already has their own config.toml with different settings at the destination; a previous partial adoption left files behind that have since been edited; the source repo gained a symlink where the user has a real file.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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