Hmbown/CodeWhale · error · anyhow::Error
loaded-image mapping for updater marker has no file inode
Error message
loaded-image mapping for updater marker has no file inode
What it means
The /proc/self/maps row containing the updater marker reports inode 0, i.e. it is an anonymous mapping with no file backing. The Android updater requires file-backed identity (device + inode) so it can prove which file on disk it is about to replace; an anonymous image cannot be updated in place, so it refuses.
Source
Thrown at crates/cli/src/update.rs:356
.context("loaded-image mapping is missing permissions")?;
let _offset = fields
.next()
.context("loaded-image mapping is missing its file offset")?;
let device = fields
.next()
.context("loaded-image mapping is missing its device")?;
let inode = fields
.next()
.context("loaded-image mapping is missing its inode")?
.parse::<u64>()
.context("loaded-image mapping has an invalid inode")?;
let path = fields.collect::<Vec<_>>().join(" ");
if permissions.as_bytes().get(2) != Some(&b'x') {
bail!("loaded-image mapping for updater marker is not executable");
}
if inode == 0 {
bail!("loaded-image mapping for updater marker has no file inode");
}
let (device_major, device_minor) = device
.split_once(':')
.context("loaded-image mapping has an invalid device")?;
let device_major = u32::from_str_radix(device_major, 16)
.context("loaded-image mapping has an invalid device major number")?;
let device_minor = u32::from_str_radix(device_minor, 16)
.context("loaded-image mapping has an invalid device minor number")?;
if path.is_empty() {
bail!("loaded-image mapping for updater marker has no pathname");
}
let mapping = AndroidImageMapping {
start,
end,
device_major,
device_minor,
inode,View on GitHub (pinned to 0c42157ee5)
Solutions
- Install the binary to a real filesystem path (e.g. /data/local/tmp or the documented install dir) and exec it from there
- Stop launching through memfd-based single-file bundlers or in-memory exec helpers
- If neither applies, report with /proc/self/maps output for the marker's row
Defensive patterns
Strategy: try-catch
Try / catch
Treat the error as terminal for in-place self-update: catch it, log the maps row details, and offer a manual download-and-replace path to the user.
Prevention
- Never execute the CLI from memfd or in-memory launchers if you need self-update
- Install to and run from a real filesystem path
- Avoid proot/sandboxes that anonymize the image mapping
When it happens
Trigger: Android self-update when the running image was created without a real file: executed from a memfd (memfd_create + fexecve), copied into anonymous memory by proot/sandboxes, or mapped by loaders that use anonymous copies.
Common situations: Running the CLI out of a memfd/ramdisk, single-file launchers that decompress-and-exec in memory, proot/Lind-style sandboxes on Android.
Related errors
- loaded-image mapping for updater marker has no pathname
- loaded-image mapping for updater marker is not executable
- multiple /proc/self/maps rows contain the updater marker
- no /proc/self/maps row contains the updater marker
- Android dladdr could not locate the updater's loaded image
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/0bd038a119871a32.
Report an issue: GitHub.