JanDeDobbeleer/oh-my-posh · error

we do not have permissions to update

Error message

we do not have permissions to update

What it means

The upgrade flow starts by creating the staging file `.<name>.new` inside the target directory (os.OpenFile with O_CREATE|O_WRONLY|O_TRUNC). If that open fails — typically a permissions problem — the upgrade aborts before downloading anything and returns this generic permissions message. The underlying OS error is logged, not included in the returned error.

Source

Thrown at src/cli/upgrade/install.go:33

// the running executable. It is exported because the terminal UI in
// cli/upgrade/tui drives it directly; this package has no UI of its own.
func Install(cfg *Config) error {
	setState(StageValidating)

	executable, err := os.Executable()
	if err != nil {
		log.Debug("failed to get executable path")
		return err
	}

	targetDir := filepath.Dir(executable)
	fileName := filepath.Base(executable)

	newPath := filepath.Join(targetDir, fmt.Sprintf(".%s.new", fileName))
	fp, err := os.OpenFile(newPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0775)
	if err != nil {
		log.Error(err)
		return errors.New("we do not have permissions to update")
	}

	setState(StageDownloading)

	data, err := downloadAndVerify(cfg)
	if err != nil {
		log.Debug("failed to download and verify")
		return err
	}

	setState(StageInstalling)

	_, err = io.Copy(fp, bytes.NewReader(data))
	// windows will have a lock when we do not close the file
	fp.Close()

	if err != nil {
		log.Debug("failed to copy data to new file")

View on GitHub (pinned to 0976794618)

Solutions

  1. Re-run the upgrade with elevated privileges (sudo/admin) matching how oh-my-posh was installed.
  2. Check ownership/permissions of the directory containing the oh-my-posh executable (ls -l $(which oh-my-posh)).
  3. If installed via a package manager, upgrade through that package manager instead of the self-upgrader.
  4. Move the installation to a user-writable location and reinstall there, then self-upgrade normally.
  5. Check for read-only mounts or disk/quota issues if the directory looks writable.

Example fix

// before (fails when binary is root-owned)
oh-my-posh upgrade
// after
sudo oh-my-posh upgrade  # or: brew upgrade oh-my-posh / apt upgrade
Defensive patterns

Strategy: validation

Validate before calling

exe, _ := os.Executable()
dir := filepath.Dir(exe)
test := filepath.Join(dir, ".write-test")
if err := os.WriteFile(test, nil, 0o644); err != nil {
    return fmt.Errorf("cannot write to %s; run with elevated privileges or use your package manager to upgrade", dir)
}
os.Remove(test)

Try / catch

if err := upgrade.Run(cfg); err != nil {
    if strings.Contains(err.Error(), "we do not have permissions to update") {
        fmt.Fprintln(os.Stderr, "binary directory is not writable; try sudo/admin or upgrade via your package manager")
        os.Exit(1)
    }
    return err
}

Prevention

When it happens

Trigger: Running the self-upgrade (Install, called from Run) where the targetDir is not writable by the current user: oh-my-posh installed via package manager/root into a system path while running as a normal user, read-only filesystem, or directory owned by another account.

Common situations: Installed with brew/apt/sudo so the binary directory is root-owned; running in CI containers with read-only /usr/local/bin; Windows Program Files-style protected directories; disk-full or quota situations.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of JanDeDobbeleer/oh-my-posh@0976794618 (2026-08-31). Data as JSON: /api/errors/0d53da685bf2e1fe. Report an issue: GitHub.