zeroclaw-labs/zeroclaw · error · anyhow::Error

cli-update-not-writable

cli-update-not-writable

Error message

install directory {$dir} is not writable ({$error}); re-run `zeroclaw update` with elevated privileges (sudo on macOS/Linux, an Administrator console on Windows)

What it means

Before installing an update, ensure_install_dir_writable probes the install directory by creating a '.zeroclaw-update-probe-<pid>' file and deleting it. If creation fails, the update aborts with the directory, the underlying OS error, and the remediation hint to re-run with sudo (macOS/Linux) or an Administrator console (Windows). This error carries the stable code 'cli-update-not-writable'.

Source

Thrown at src/commands/update.rs:840

        Some("x86")
    } else if cfg!(target_arch = "arm") {
        Some("arm")
    } else {
        None
    }
}

async fn ensure_install_dir_writable(exe: &Path) -> Result<()> {
    let dir = exe
        .parent()
        .context("cannot determine install directory for the current executable")?;
    let probe = dir.join(format!(".zeroclaw-update-probe-{}", std::process::id()));
    match tokio::fs::File::create(&probe).await {
        Ok(_) => {
            let _ = tokio::fs::remove_file(&probe).await;
            Ok(())
        }
        Err(e) => bail!(install_dir_not_writable_message(
            &dir.display().to_string(),
            &e.to_string()
        )),
    }
}

#[cfg(not(windows))]
async fn swap_binary(new: &Path, target: &Path) -> Result<()> {
    tokio::fs::remove_file(target)
        .await
        .context("failed to remove old binary")?;
    tokio::fs::copy(new, target)
        .await
        .context("failed to write new binary")?;
    Ok(())
}

#[cfg(windows)]

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Re-run the update with elevated privileges exactly as the message suggests: `sudo zeroclaw update` on macOS/Linux or an Administrator console on Windows.
  2. For a user-owned setup instead: `sudo chown $(whoami) <install-dir>` so future updates need no elevation.
  3. Or move the binary to a user-writable directory already on PATH (e.g. ~/.local/bin) and update from there.
  4. If you expected the directory to be writable, check the embedded OS error for the real cause (read-only mount, deleted directory, ACL).

Example fix

# before: unprivileged update into root-owned dir fails
zeroclaw update   # -> install directory ... is not writable
# after: elevate, or take ownership once
sudo zeroclaw update
sudo chown $(whoami) /usr/local/bin && zeroclaw update
Defensive patterns

Strategy: validation

Validate before calling

use std::fs;
fn install_dir_writable(dir: &std::path::Path) -> bool {
    let probe = dir.join(format!(".zc-probe-{}", std::process::id()));
    match fs::File::create(&probe) {
        Ok(_) => { let _ = fs::remove_file(&probe); true }
        Err(_) => false,
    }
}
// call before running the update; if false, elevate or fix ownership first

Try / catch

match run_update().await {
    Err(e) if e.to_string().contains("is not writable") => {
        // re-invoke with sudo (or fix dir ownership), then retry once
    }
    other => other,
}

Prevention

When it happens

Trigger: `zeroclaw update` when the directory holding the current zeroclaw binary is not writable by the invoking user: binary in /usr/local/bin owned by root, a read-only mount, a system-protected path, or (ENOENT variants) an install directory that no longer exists.

Common situations: Binary initially installed with sudo or by a package manager into a root-owned path; corporate lockdown with read-only /usr/local; running the update from an unprivileged service account.

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 zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/5c090363fbacb3a0. Report an issue: GitHub.