nikivdev/code · error

You don't have write permission to {} because it's owned by

Error message

You don't have write permission to {} because it's owned by root.
Consider updating flow through your package manager if installed from it.
Otherwise run `f upgrade` as root.

What it means

`check_write_permission` (src/upgrade.rs:~520) detects, via `fs::metadata(...).uid()` vs `libc::getuid()`, that the install path (or its parent) is owned by root while the current user is not, so a self-upgrade cannot replace the binary. It bails with an explanatory message pointing to the package manager or running as root.

Source

Thrown at src/upgrade.rs:528

/// Get the path to the current executable.
fn current_exe_path() -> Result<PathBuf> {
    env::current_exe().context("Failed to get current executable path")
}

/// Check write permissions for the executable path.
fn check_write_permission(path: &Path) -> Result<()> {
    let parent = path.parent().unwrap_or(path);

    #[cfg(unix)]
    {
        use std::os::unix::fs::MetadataExt;

        let metadata = fs::metadata(path).or_else(|_| fs::metadata(parent))?;
        let uid = unsafe { libc::getuid() };

        if metadata.uid() == 0 && uid != 0 {
            bail!(
                "You don't have write permission to {} because it's owned by root.\n\
                 Consider updating flow through your package manager if installed from it.\n\
                 Otherwise run `f upgrade` as root.",
                path.display()
            );
        }
    }

    // Try to check if we can write
    if path.exists() {
        let metadata = fs::metadata(path)?;
        if metadata.permissions().readonly() {
            bail!("You do not have write permission to {}", path.display());
        }
    } else if !parent.exists() || fs::metadata(parent)?.permissions().readonly() {
        bail!("You do not have write permission to {}", parent.display());
    }

View on GitHub (pinned to a747e741ae)

Solutions

  1. Update through the package manager that installed it (apt/dnf/brew), which handles permissions.
  2. Run `sudo f upgrade` so the root-owned binary can be replaced.
  3. Install flow into a user-writable directory (e.g. ~/.local/bin) and ensure it precedes system paths on PATH.
  4. chown the install location to your user if you own the machine: `sudo chown -R $(whoami) <dir>`.

Example fix

// before (fails as normal user)
f upgrade
// after
sudo f upgrade   # or: use your package manager, e.g. `apt upgrade flow`
Defensive patterns

Strategy: validation

Validate before calling

# predict the root-owned failure before upgrading
BIN="$(command -v f)"
[ "$(stat -c %u "$BIN")" = 0 ] && [ "$(id -u)" != 0 ] && echo "need sudo or package manager" || echo "ok to self-upgrade"

Prevention

When it happens

Trigger: Binary installed to a root-owned location such as /usr/local/bin, /usr/bin, or via apt/brew-as-root; `metadata.uid() == 0 && libc::getuid() != 0`.

Common situations: Installed with `sudo` or via a system package manager (apt/dnf/pacman) and later running `f upgrade` as a normal user; shared workstation where an admin placed the binary.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/12a3a958d2142d3c. Report an issue: GitHub.