{"record":{"id":"3944b3810ae61066","repo":"gitbutlerapp/gitbutler","slug":"found-existing-but-symlink-pointing-to-existin","errorCode":null,"errorMessage":"Found existing 'but' symlink pointing to: {existing_target_str}","messagePattern":"Found existing 'but' symlink pointing to: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":153,"sourceCode":"        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\") {\n            Some(Channel::Nightly)\n        } else if existing_target_str.contains(\"/GitButler.app/\") {\n            Some(Channel::Release)\n        } else {\n            None\n        };\n\n        if previous_channel.is_none() {\n            warn(&format!(\n                \"Found existing 'but' symlink pointing to: {existing_target_str}\"\n            ));\n            warn(\"This will be replaced with GitButler's 'but' command\");\n            info(\n                \"Note: Your custom symlink setup will be overwritten. The original target is not a GitButler installation.\",\n            );\n        }\n    }\n\n    // Create temporary symlink to test the new installation\n    let new_app_macos_dir = install_app_new.join(\"Contents/MacOS/gitbutler-tauri\");\n    let _ = fs::remove_file(&but_new);\n\n    unix_fs::symlink(&new_app_macos_dir, &but_new)?;\n\n    // Verify the new installation works\n    let verify_status = Command::new(&but_new)\n        .arg(\"--version\")","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/install_macos.rs#L135-L171","documentation":"Warning from the macOS installer when ~/.local/bin/but is a symlink whose target is neither a Nightly build (target string contains 'Nightly') nor a GitButler.app release (contains '/GitButler.app/'). The installer classifies it as a custom, non-GitButler symlink (previous_channel is None) and warns because the final swap step will overwrite it with a symlink to the new app bundle. It is purely informational; the install proceeds.","triggerScenarios":"Existing symlink created by the user, e.g. ln -s ~/.cargo/bin/but ~/.local/bin/but, a self-compiled build in ~/builds/but, or a symlink to an unrelated tool that also happens to be named 'but'. Channel detection at install_macos.rs:144-150 fails both the 'Nightly' and '/GitButler.app/' substring checks, so previous_channel is None and the warn fires at line 153.","commonSituations":"Dotfile-managed symlinks; switching from a source-build CLI to the desktop-app-installed one; tool name collision with another 'but' binary; stale symlink left behind after moving a self-built app.","solutions":["Note the target printed in the warning, then let the installer overwrite it; re-create your custom link afterwards if it pointed at something you still need (ln -sfn /your/target ~/.local/bin/but)","Preempt the warning by removing the symlink before installing: rm ~/.local/bin/but","If the target was a cargo-installed CLI you still want, keep it reachable via its original path (e.g. ~/.cargo/bin/but is already on PATH)","Confirm after install: readlink ~/.local/bin/but should show .../GitButler.app/Contents/MacOS/gitbutler-tauri"],"exampleFix":"# before\nreadlink ~/.local/bin/but\n/Users/me/.cargo/bin/but            # custom target, will be overwritten\n\n# after install - restore your custom link under another name if needed\nln -sfn /Users/me/.cargo/bin/but ~/.local/bin/but-custom","handlingStrategy":"validation","validationCode":"# Before installing, see what the symlink points at:\ntarget=$(readlink ~/.local/bin/but 2>/dev/null)\nif [ -n \"$target\" ] && ! [[ \"$target\" == *GitButler.app* ]] && ! [[ \"$target\" == *Nightly* ]]; then\n  echo \"custom symlink -> $target will be replaced by the installer\"\n  echo \"$target\" > ~/but-symlink.bak   # persist it yourself\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Record 'readlink ~/.local/bin/but' before every install; the installer only logs the target, it does not save it","Keep personal symlinks under different names (but-custom) so GitButler's 'but' never collides","After install, verify 'readlink ~/.local/bin/but' points into GitButler.app"],"tags":["macos","installer","symlink","overwrite","cli"],"backgroundTag":"symlink-conflict","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}