{"record":{"id":"3ac7058d1d7ba5a7","repo":"gitbutlerapp/gitbutler","slug":"a-but-binary-already-exists-at-not-a-symlink","errorCode":null,"errorMessage":"A 'but' binary already exists at {} (not a symlink)","messagePattern":"A 'but' binary already exists at (.+?) \\(not a symlink\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":126,"sourceCode":"    }\n\n    // Create bin directory\n    let bin_dir = home_dir.join(\".local/bin\");\n    fs::create_dir_all(&bin_dir)?;\n\n    // Check for existing 'but' and detect channel switching\n    let but_symlink = bin_dir.join(\"but\");\n    let but_new = bin_dir.join(\"but.new\");\n\n    if but_symlink.exists() && !but_symlink.is_symlink() {\n        // 'but' exists but is not a symlink\n        let now = std::time::SystemTime::now()\n            .duration_since(std::time::UNIX_EPOCH)\n            .unwrap_or_default()\n            .as_secs();\n        let timestamp = format!(\"{now}\");\n        let but_backup = bin_dir.join(format!(\"but.backup.{timestamp}\"));\n        warn(&format!(\n            \"A 'but' binary already exists at {} (not a symlink)\",\n            but_symlink.display()\n        ));\n        warn(&format!(\n            \"Moving it to {} to preserve your existing file\",\n            but_backup.display()\n        ));\n        fs::rename(&but_symlink, &but_backup)?;\n        info(&format!(\n            \"Your original 'but' has been saved to: {}\",\n            but_backup.display()\n        ));\n    } else if but_symlink.is_symlink() {\n        let existing_target = fs::read_link(&but_symlink)?;\n        let existing_target_str = existing_target.to_string_lossy();\n\n        // Detect channel switching\n        let previous_channel = if existing_target_str.contains(\"Nightly\") {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/install_macos.rs#L108-L144","documentation":"While wiring up the 'but' CLI symlink in the bin directory, install_app on macOS finds an existing non-symlink file at the symlink target path. It warns that a real 'but' binary already exists and that it will be moved aside (to but.backup.<timestamp>) to preserve the user's file before creating the symlink.","triggerScenarios":"Raised in install_app (download_and_install_app) when the path bin_dir/but exists but is not a symlink — i.e. a previous install copied a real binary there, or the user placed a custom build named 'but' in their PATH directory.","commonSituations":"Upgrading from an install method that copied the binary instead of symlinking; a locally built 'but' binary sitting in ~/.local/bin or /usr/local/bin; package-manager-managed 'but' binary colliding with the installer's symlink.","solutions":["Let the installer proceed: your existing binary is preserved as but.backup.<timestamp> in the same directory.","If you want to keep your custom build authoritative, remove it from the installer's bin dir or point the installer at a different bin directory.","Delete the stale binary yourself first if you no longer need it (rm <bin_dir>/but) and re-run the installer.","Check whether a package manager owns the binary (e.g. dpkg -S / brew list) and uninstall it there to avoid the collision recurring."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Detect a non-symlink 'but' in your bin dir before installing\nimport os\ndef but_is_symlink(bin_dir):\n    p = os.path.join(bin_dir, 'but')\n    return os.path.islink(p) or not os.path.exists(p)","typeGuard":null,"tryCatchPattern":"// Move aside any real file before creating the symlink\nif path.is_file() && !path.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false) {\n    let backup = bin_dir.join(format!(\"but.backup.{}\", timestamp()));\n    fs::rename(&path, &backup)?;\n}","preventionTips":["Use one installation method consistently (don't mix copied binaries and symlinked installs)","Check which package manager owns an existing 'but' binary (which -a but) before installing","Keep custom builds out of the installer's target bin directory"],"tags":["macos","installer","symlink","conflict"],"backgroundTag":"file-already-exists","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}