gitbutlerapp/gitbutler · warning

Cannot write to ( )

Error message

Cannot write to {} ({})

What it means

In setup_shell_config (but-installer/src/shell.rs), when appending the 'but' shell integration lines to a detected shell config file fails (std::io error), the installer warns with the config path and a mapped reason (permission denied / file not found / other) and then prints manual instructions so the user can add the lines themselves. Installation continues; only the automatic config step failed.

Solutions

  1. Follow the printed manual instructions: copy the shown lines into your shell config file by hand.
  2. Fix permissions on the config file/directory (`chown $USER ~/.zshrc; chmod u+w ~/.zshrc`) and re-run the installer.
  3. Create the missing config file if it does not exist (`touch ~/.zshrc`) and re-run.
  4. Check for immutable/managed dotfiles (`lsattr`, `chattr -i`) and unlock if applicable.

Example fix

# before
$ ./but-installer   # "Cannot write to /home/me/.zshrc (permission denied)"
# after
$ ls -l ~/.zshrc    # owned by root?
$ sudo chown me:me ~/.zshrc && chmod u+w ~/.zshrc
$ ./but-installer
Defensive patterns

Strategy: try-catch

Validate before calling

# Pre-check writability before running the installer.
test -w ~/.zshrc || echo 'config not writable: fix ownership/permissions first'
[ -f ~/.zshrc ] || touch ~/.zshrc

Try / catch

try {
  fs.appendFileSync(configPath, integrationLines);
} catch (e) {
  console.warn(`Cannot write to ${configPath} (${e.code ?? e.message}); add these lines manually:`);
  console.log(integrationLines);
}

Prevention

When it happens

Trigger: setup_shell_config (called by setup_config) attempts to write to the detected config path (e.g. ~/.bashrc, ~/.zshrc) and the write returns Err - typically ErrorKind::PermissionDenied or NotFound.

Common situations: Running the installer as a different user than the config owner; read-only home directory or NFS-mounted home; config file missing and directory creation also failing; enterprise-managed machines with immutable dotfiles.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/91045d857cb70fad. Report an issue: GitHub.

Appendix: source

Thrown at crates/but-installer/src/shell.rs:301

            ));

            if needs_path {
                ui::println_empty();
                info("To use 'but' in this terminal session, you may need to run:");
                ui::println(&format!("  source \"{}\"", cfg.config_path.display()));
                ui::println_empty();
                info("Or close and reopen your terminal");
            }
        }
        Err(e) => {
            use std::io::ErrorKind;
            let error_msg = match e.kind() {
                ErrorKind::PermissionDenied => "permission denied".to_string(),
                ErrorKind::NotFound => "file not found".to_string(),
                _ => format!("{e}"),
            };

            warn(&format!(
                "Cannot write to {} ({})",
                cfg.config_path.display(),
                error_msg
            ));
            info("Please add the following lines to your shell config file manually:");

            if needs_path {
                ui::println(&format!("  {path_cmd}"));
            }
            if needs_completions {
                ui::println(&format!("  {completion_cmd}"));
            }
        }
    }

    Ok(())
}

View on GitHub (pinned to 58e5313667)