Hmbown/CodeWhale · error · anyhow::Error

no /proc/self/maps row contains the updater marker

Error message

no /proc/self/maps row contains the updater marker

What it means

On Android the updater must prove which on-disk file the running executable was loaded from. It scans /proc/self/maps for a row whose [start, end) range contains a marker address taken from the CLI's own code image. This error means the scan finished without any row covering the marker, so the loaded image could not be attributed to a file and self-update is refused.

Source

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

            .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,
            path: PathBuf::from(path),
        };
        if matching.replace(mapping).is_some() {
            bail!("multiple /proc/self/maps rows contain the updater marker");
        }
    }

    matching.ok_or_else(|| anyhow!("no /proc/self/maps row contains the updater marker"))
}

#[cfg(all(test, unix))]
fn resolve_android_loaded_executable_report(
    maps: &str,
    marker: u64,
    dladdr_path: &Path,
) -> Result<PathBuf> {
    Ok(android_loaded_executable_proof_report(maps, marker, dladdr_path)?.path)
}

#[cfg(any(target_os = "android", all(test, unix)))]
fn android_loaded_executable_proof_report(
    maps: &str,
    marker: u64,
    dladdr_path: &Path,
) -> Result<AndroidExecutableProof> {
    let mapping = parse_android_image_mapping(maps, marker)?;

View on GitHub (pinned to 8880682c63)

Solutions

  1. Inspect the live process (adb shell cat /proc/<pid>/maps): if the executable rows have no pathname, that Android build hides them and self-update from that location is unsupported; install the binary on a mapped path instead
  2. If this is a test fixture, add a row like '7f0000000000-7f0000001000 r-xp 00000000 fd:01 1337 /data/local/tmp/codewhale' whose range covers the marker, has executable permission, nonzero inode, and a pathname
  3. Update to a newer Codewhale build: the Android proof logic also consults dladdr as a second authority and may succeed where the maps scan alone cannot
  4. If the process runs from memfd or an interpreter, launch the real binary file so it gets a file-backed mapping

Example fix

// test fixture: before (marker 0x7f0000000042 is not covered)
let maps = "00000000-00010000 r-xp 00000000 fd:01 10 /system/bin/linker64\n";

// after: add a row that covers the marker
let maps = "00000000-00010000 r-xp 00000000 fd:01 10 /system/bin/linker64\n\n7f0000000000-7f0000001000 r-xp 00000000 fd:01 1337 /data/local/tmp/codewhale\n";
Defensive patterns

Strategy: try-catch

Validate before calling

// Before invoking the proof path, verify the maps text covers the marker:
fn maps_cover_marker(maps: &str, marker: u64) -> bool {
    maps.lines().any(|line| {
        let mut fields = line.split_whitespace();
        let range = match fields.next() { Some(r) => r, None => return false };
        let (s, e) = match range.split_once('-') { Some(p) => p, None => return false };
        match (u64::from_str_radix(s, 16), u64::from_str_radix(e, 16)) {
            (Ok(s), Ok(e)) => s <= marker && marker < e,
            _ => false,
        }
    })
}

Try / catch

Treat the Err as 'cannot self-update on this Android layout': report to the user and skip replacement rather than retrying. The maps/marker relationship is stable for the life of the process, so retries cannot succeed.

Prevention

When it happens

Trigger: parse_android_image_mapping runs with the /proc/self/maps text and the marker address; it fires when no row satisfies start <= marker < end: the maps snapshot does not describe this process, the image is only in anonymous/JIT mappings (no pathname), or a test passes fixture maps whose ranges all miss the marker.

Common situations: Android 10+ replaces app-data executable paths in /proc/self/maps with unnamed mappings; running under instrumentation (gdbserver, wrap.sh) or from an interpreter such as app_process; emulators with unusual layouts; unit tests with hand-written maps fixtures that forget to cover the marker address.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/3e1557602abb5208. Report an issue: GitHub.