Hmbown/CodeWhale · error · anyhow::Error
Android loaded-image identity changed: /proc/self/maps has d
Error message
Android loaded-image identity changed: /proc/self/maps has device/inode {:x}:{:x}:{}, but update target {} is {:x}:{:x}:{}; refusing to replace it What it means
validate_android_mapping_identity stats the candidate update target and compares device major/minor plus inode against the /proc/self/maps row captured for the running image. A mismatch means the file at that path was replaced after the process started, so replacing it now could overwrite an unrelated file; the updater refuses (a deliberate TOCTOU guard).
Source
Thrown at crates/cli/src/update.rs:487
#[cfg(any(target_os = "android", all(test, unix)))]
fn validate_android_mapping_identity(
mapping: &AndroidImageMapping,
candidate: &Path,
) -> Result<()> {
use std::os::unix::fs::MetadataExt;
let candidate_metadata = std::fs::metadata(candidate).with_context(|| {
format!(
"failed to stat Android update target {}",
candidate.display()
)
})?;
let (candidate_major, candidate_minor) = android_device_parts(candidate_metadata.dev());
let identity_matches = mapping.device_major == candidate_major
&& mapping.device_minor == candidate_minor
&& mapping.inode == candidate_metadata.ino();
if !identity_matches {
bail!(
"Android loaded-image identity changed: /proc/self/maps has device/inode {:x}:{:x}:{}, but update target {} is {:x}:{:x}:{}; refusing to replace it",
mapping.device_major,
mapping.device_minor,
mapping.inode,
candidate.display(),
candidate_major,
candidate_minor,
candidate_metadata.ino()
);
}
Ok(())
}
#[cfg(any(target_os = "android", all(test, unix)))]
fn android_device_parts(device: u64) -> (u32, u32) {
// Linux/Bionic's dev_t encoding, matching makedev(3), major(3), and
// minor(3). `/proc/self/maps` renders these components in hexadecimal.
let major = ((device >> 8) & 0xfff) as u32;View on GitHub (pinned to 0c42157ee5)
Solutions
- Restart the CLI so it captures the new file's identity, then update again
- Run only one self-update at a time; serialize updates in scripts
- Avoid package-manager upgrades and self-update operating on the same install simultaneously
Defensive patterns
Strategy: try-catch
Try / catch
Catch the identity-mismatch error and prompt a restart of the CLI; a fresh process re-captures device/inode from the new file and the next update attempt passes.
Prevention
- Serialize self-updates: one updater per install at a time
- Keep package-manager upgrades and self-update from touching the same path concurrently
- Restart the process after any in-place replacement before updating again
When it happens
Trigger: Android self-update while the underlying file changed since process start: a second updater ran concurrently, a package manager reinstalled the package, or the file was swapped by an installer between launch and update.
Common situations: Two codewhale update runs racing, pm/app-store upgrade racing a self-update, scripts that replace the binary while a long-lived session is open.
Related errors
- Android loaded-image proof changed from {:?} to {:?}; refusi
- Android dladdr could not locate the updater's loaded image
- Android dladdr returned an empty loaded-image path
- loaded-image mapping for updater marker is not executable
- loaded-image mapping for updater marker has no file inode
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/cf8217554dabc24c.
Report an issue: GitHub.