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

  1. Install the binary to a real filesystem path (e.g. /data/local/tmp or the documented install dir) and exec it from there
  2. Stop launching through memfd-based single-file bundlers or in-memory exec helpers
  3. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/0bd038a119871a32. Report an issue: GitHub.