gitbutlerapp/gitbutler · warning

Found existing 'but' symlink pointing to

Error message

Found existing 'but' symlink pointing to: {existing_target_str}

What it means

During macOS installation, install_app checks the target path of an existing 'but' symlink in a bin directory. If the symlink's target does not resolve to a GitButler installation (previous_channel is None), the installer emits this warning including the existing target string before overwriting it. It is a heads-up that a user-managed symlink is about to be replaced.

Solutions

  1. Inspect the reported target with `readlink $(which but)`; if it belongs to another tool, rename that tool's binary or adjust your PATH before installing.
  2. Accept the warning if you no longer need the custom 'but' command - the installer will overwrite the symlink to point at GitButler.
  3. Re-install/restore the other tool afterwards under a different name if you still need both commands.

Example fix

// before: unaware the custom symlink is clobbered
$ brew install gitbutler
// after: check and preserve the old target first
$ readlink /usr/local/bin/but   # note target
$ mv /usr/local/bin/but /usr/local/bin/my-but
$ # then run the GitButler installer
Defensive patterns

Strategy: validation

Validate before calling

const but = '/usr/local/bin/but';
if (fs.existsSync(but) && fs.lstatSync(but).isSymbolicLink()) {
  const target = fs.readlinkSync(but);
  if (!target.includes('gitbutler')) {
    console.warn(`Existing non-GitButler 'but' symlink -> ${target}; back it up before installing.`);
  }
}

Type guard

function isGitButlerSymlink(linkPath: string): boolean {
  try { return fs.readlinkSync(linkPath).includes('gitbutler'); } catch { return false; }
}

Prevention

When it happens

Trigger: Running the GitButler macOS installer (via download_and_install_app -> install_app) when /usr/local/bin/but (or equivalent) already exists as a symlink whose target is not a GitButler binary (e.g. points to a homebrew formula or a custom tool also named 'but').

Common situations: Users who previously aliased 'but' to some other tool (e.g. branch-util scripts, homebrew packages) install GitButler and the installer detects the conflict; environments with pre-existing PATH shims named 'but'; machines shared between tools using the same command name.

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 gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/3944b3810ae61066. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-installer/src/install_macos.rs:153

        info(&format!(
            "Your original 'but' has been saved to: {}",
            but_backup.display()
        ));
    } else if but_symlink.is_symlink() {
        let existing_target = fs::read_link(&but_symlink)?;
        let existing_target_str = existing_target.to_string_lossy();

        // Detect channel switching
        let previous_channel = if existing_target_str.contains("Nightly") {
            Some(Channel::Nightly)
        } else if existing_target_str.contains("/GitButler.app/") {
            Some(Channel::Release)
        } else {
            None
        };

        if previous_channel.is_none() {
            warn(&format!(
                "Found existing 'but' symlink pointing to: {existing_target_str}"
            ));
            warn("This will be replaced with GitButler's 'but' command");
            info(
                "Note: Your custom symlink setup will be overwritten. The original target is not a GitButler installation.",
            );
        }
    }

    // Create temporary symlink to test the new installation
    let new_app_macos_dir = install_app_new.join("Contents/MacOS/gitbutler-tauri");
    let _ = fs::remove_file(&but_new);

    unix_fs::symlink(&new_app_macos_dir, &but_new)?;

    // Verify the new installation works
    let verify_status = Command::new(&but_new)
        .arg("--version")

View on GitHub (pinned to 58e5313667)