{"record":{"id":"b435aea1eb110ffb","repo":"gitbutlerapp/gitbutler","slug":"would-probably-need-to-run-ln-sf-unix-lin","errorCode":null,"errorMessage":"Would probably need to run \"ln -sf '{}' '{UNIX_LINK_PATH}'\"{privilege}","messagePattern":"Would probably need to run \"ln -sf '(.+?)' '(.+?)'\"(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/but-action/src/cli.rs","lineNumber":100,"sourceCode":"            // dedicated Code so the frontend can react based on the code\n            // rather than matching on an English message.\n            Err(\n                anyhow!(\"osascript exited with status 1\").context(ErrorContext::new_static(\n                    Code::CliInstallCancelled,\n                    \"CLI install cancelled\",\n                )),\n            )\n        } else {\n            Err(anyhow!(\n                \"osascript exited with status {}\",\n                status\n                    .code()\n                    .map(|c| c.to_string())\n                    .unwrap_or_else(|| \"unknown\".into())\n            ))\n        }\n    } else {\n        Err(anyhow!(\n            \"Would probably need to run \\\"ln -sf '{}' '{UNIX_LINK_PATH}'\\\"{privilege}\",\n            cli_path.display(),\n            privilege = if can_elevate_privileges {\n                \" with root permissions\"\n            } else {\n                \"\"\n            }\n        ))\n    }\n}\n\nfn ensure_cli_path_exists_prior_to_link(cli_path: &std::path::Path) -> anyhow::Result<()> {\n    if cli_path.exists() {\n        return Ok(());\n    }\n    bail!(\"Run `CARGO_TARGET_DIR=$PWD/target/tauri cargo build -p but` to build the `but` binary\")\n}\n","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-action/src/cli.rs#L82-L118","documentation":"Returned by the CLI installer when it cannot create the /usr/local/bin/but symlink itself and falls back to instructing the user. It is reached when the earlier direct symlink attempts failed (no permission on /usr/local/bin), the platform is not macOS, or InstallMode::CurrentUserOnly disallows elevation. The message contains the exact ln -sf command to run, optionally suffixed with ' with root permissions'.","triggerScenarios":"do_install_cli on Linux (any mode), or on macOS with CurrentUserOnly: the non-privileged std::os::unix::fs::symlink into /usr/local/bin fails with permission denied, control falls past the osascript branch, and the else-branch returns this instruction error.","commonSituations":"Linux systems where /usr/local/bin is root-owned; macOS users choosing 'current user only'; headless or automation contexts where no interactive privilege prompt is possible; dev builds where the but binary does not exist yet (that trips a different message first).","solutions":["Run the exact command from the error message: sudo ln -sf '<printed-cli-path>' /usr/local/bin/but","Or install into a directory you own that is on PATH: mkdir -p ~/bin && ln -sf '<cli>' ~/bin/but","On macOS, retry with AllowPrivilegeElevation so the osascript path performs the privileged link","Verify the cli binary exists at the printed path before linking (dev builds: build the but binary first)"],"exampleFix":"# before: install returns \"Would probably need to run \\\"ln -sf ...\\\"\"\n# after: run the printed command\nsudo ln -sf '/path/to/but' /usr/local/bin/but\n# or user-local alternative:\nmkdir -p ~/bin && ln -sf '/path/to/but' ~/bin/but\necho 'export PATH=\"$HOME/bin:$PATH\"' >> ~/.profile","handlingStrategy":"fallback","validationCode":"// can we write /usr/local/bin without elevation?\nlet probe = std::path::Path::new(\"/usr/local/bin/.probe\");\nlet unprivileged = std::fs::write(probe, b\"\").is_ok();\nlet _ = std::fs::remove_file(probe);\nif !unprivileged {\n    // expect the manual-instruction error; guide the user up front\n}","typeGuard":null,"tryCatchPattern":"match do_install_cli(mode) {\n    Err(e) if e.to_string().contains(\"Would probably need to run\") => {\n        // extract the ln -sf command from the message and run/guide it\n    }\n    r => r,\n}","preventionTips":["Pre-create the symlink in deployment scripts","Prefer a user-writable PATH dir in locked-down environments","Check the but binary exists before triggering install"],"tags":["cli-install","symlink","unix","permissions","manual-steps"],"backgroundTag":"manual-install-required","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}