Hmbown/CodeWhale · error

Refusing to replace : its bytes differ from the running…

Error message

Refusing to replace {}: its bytes differ from the running executable. This may be another installation or an unrelated command. No command is removed automatically.

{GITHUB_MIGRATION_HELP}

What it means

Before replacing a file, the updater hashes it (sha256) and compares against the running executable's hash (identity.file_hash). If the bytes differ, the target is some other installation or an unrelated command that merely shares the name, so the updater refuses — no command is ever removed automatically.

Solutions

  1. Identify which copy you actually use (`which -a codewhale`, compare hashes) and run update from the binary you want updated.
  2. Remove the foreign/stale binary manually after confirming it is not yours; the updater will not delete it for you.
  3. Reinstall from the official installer so only one managed copy exists, then update.

Example fix

// before: stale v0.1 binary next to running v0.2 refuses replacement
$ sha256sum ~/.local/bin/codewhale  # differs from running binary
// after: delete the stale copy yourself, then update
$ rm ~/.local/bin/codewhale-old && codewhale update
Defensive patterns

Strategy: validation

Validate before calling

use sha2::{Digest, Sha256};
fn matches_running_binary(path: &std::path::Path, expected: &str) -> bool {
    std::fs::read(path).map(|b| Sha256::digest(&b) == *expected.as_bytes()).unwrap_or(false)
}

Prevention

When it happens

Trigger: validate_update_target reads the target file and its sha256_hex does not equal identity.file_hash; raised for stale copies from older versions, different builds, or unrelated binaries placed next to the real one.

Common situations: Two independent installations of codewhale exist (one built from source, one downloaded); a different tool was named `codewhale` in the same bin dir; the binary was modified/patched after install.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/37be56bd958ff2c9. Report an issue: GitHub.

Appendix: source

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

        Ok(metadata) => metadata,
        Err(error) if error.kind() == std::io::ErrorKind::NotFound && target != identity.path => {
            return Ok(());
        }
        Err(error) => {
            return Err(error)
                .with_context(|| format!("failed to inspect update target {}", target.display()));
        }
    };
    if !metadata.is_file() || metadata.is_symlink() {
        bail!(
            "Refusing to replace {}: the update target is not a regular file.\n\n{GITHUB_MIGRATION_HELP}",
            target.display()
        );
    }
    let bytes = std::fs::read(target)
        .with_context(|| format!("failed to identify update target {}", target.display()))?;
    if sha256_hex(&bytes) != identity.file_hash {
        bail!(
            "Refusing to replace {}: its bytes differ from the running executable. This may be another installation or an unrelated command. No command is removed automatically.\n\n{GITHUB_MIGRATION_HELP}",
            target.display()
        );
    }
    Ok(())
}

fn protected_update_path(path: &Path) -> bool {
    [
        "/usr/bin",
        "/usr/sbin",
        "/bin",
        "/sbin",
        "/nix/store",
        "/gnu/store",
    ]
    .iter()
    .any(|prefix| path.starts_with(prefix))

View on GitHub (pinned to 73e0f67d83)