Hmbown/CodeWhale · error

staged update is not executable (mode ); refusing to replace

Error message

staged update {} is not executable (mode {:03o}); refusing to replace {}

What it means

Thrown during the atomic install step of self-update. After staging the new binary to a temp file, the updater checks that the staged file has any execute permission bit (0o111); if not (mode bits shown in octal), it refuses to replace the current binary rather than installing an unrunnable executable.

Solutions

  1. Re-run the update so the staged binary is written with mode 0755 (set executable bits on extraction).
  2. Fix the extraction code to apply Unix permissions from the archive entries.
  3. Check the release archive: confirm the binary entry has executable permissions and rebuild it if not.
  4. Ensure the target filesystem supports execute permissions (not mounted noexec).

Example fix

// before
fs::write(&staged_path, bytes)?;
// after
fs::write(&staged_path, bytes)?;
let mut perms = fs::metadata(&staged_path)?.permissions();
use std::os::unix::fs::PermissionsExt;
perms.set_mode(0o755);
fs::set_permissions(&staged_path, perms)?;
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::PermissionsExt;
let mode = std::fs::metadata(&staged)?.permissions().mode();
if mode & 0o111 == 0 {
    eprintln!("staged binary {staged:?} not executable (mode {mode:03o}); fix extraction or mount", );
    return Err(anyhow!("staged binary not executable"));
}

Prevention

When it happens

Trigger: Self-update reaches the persist step but the extracted/staged temp binary lacks execute bits — typically when the archive stored the file mode 0644 or the extraction lost permissions.

Common situations: Extraction tool or code copied the file without preserving the mode bit; extracting on a filesystem that does not support Unix permissions; a packaging bug in the release archive.

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 Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/149b236e37f63bce. Report an issue: GitHub.

Appendix: source

Thrown at crates/cli/src/update.rs:1893

    // Independently verify the staged binary is executable before it may
    // replace the target; a chmod that silently did not stick would otherwise
    // install a binary that cannot run.
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        let staged_mode = tmp
            .as_file()
            .metadata()
            .with_context(|| {
                format!(
                    "failed to inspect staged update at {}",
                    tmp.path().display()
                )
            })?
            .permissions()
            .mode();
        if staged_mode & 0o111 == 0 {
            bail!(
                "staged update {} is not executable (mode {:03o}); refusing to replace {}",
                tmp.path().display(),
                staged_mode & 0o7777,
                target.display()
            );
        }
    }

    validate_before_replace()?;

    #[cfg(windows)]
    {
        let backup = backup_path_for(target);
        if target.exists() {
            std::fs::rename(target, &backup).with_context(|| {
                format!(
                    "failed to move current executable {} to {}",
                    target.display(),

View on GitHub (pinned to 73e0f67d83)