astrid-runtime/astrid · error

invalid mount escape

Error message

invalid mount escape

What it means

Raised when the escape decoder sees a backslash but the 3 following bytes cannot be retrieved (slice out of bounds) while decoding mount paths. Since escape_end <= bytes.len() was already checked, this indicates malformed internal index bookkeeping; the library converts it to InvalidData 'invalid mount escape'.

Solutions

  1. Regenerate the encoded mount path from the real canonical path instead of repairing bytes by hand
  2. Verify the input string only contains valid \\NNN octal escapes (3 octal digits after backslash)
  3. Ensure the string passed in was produced by the library's own encoder, not transformed elsewhere (e.g. JSON escaping)
  4. Add a pre-check that every backslash in the input is followed by exactly three octal digits

Example fix

// before
verify_mount_path("\\12x malformed");
// after
verify_mount_path("\\101 r \\165 n"); // valid \\NNN octal escapes only
Defensive patterns

Strategy: validation

Validate before calling

fn escapes_valid(s: &str) -> bool {
    let b = s.as_bytes();
    (0..b.len()).all(|i| b[i] != b'\\' || (i + 4 <= b.len() && b[i+1..i+4].iter().all(|d| (b'0'..=b'7').contains(d))))
}

Type guard

fn is_octal_escape(b: &[u8], i: usize) -> bool {
    i + 4 <= b.len() && b[i] == b'\\' && b[i+1..i+4].iter().all(|d| (b'0'..=b'7').contains(d))
}

Try / catch

match verify_mount_path(canonical, encoded) {
    Err(e) if e.to_string().contains("invalid mount escape") => eprintln!("malformed escape in path record"),
    r => r?,
}

Prevention

When it happens

Trigger: Decoding an encoded mount path where the slice get(escape_start..escape_end) unexpectedly returns None during escape processing.

Common situations: Corrupted or hand-edited encoded path records; inconsistent bounds after a prior overflow check; fuzzed or adversarial input to the path-verification API.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/8dc556eb408959c6. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-kernel/src/lib.rs:4416

    let canonical = std::fs::canonicalize(path)?;
    let mountinfo = std::fs::read_to_string("/proc/self/mountinfo")?;
    for line in mountinfo.lines() {
        let Some(encoded) = line.split_whitespace().nth(4) else {
            continue;
        };
        let mut decoded = Vec::with_capacity(encoded.len());
        let bytes = encoded.as_bytes();
        let mut index = 0;
        while index < bytes.len() {
            let escape_end = index.checked_add(4).ok_or_else(|| {
                std::io::Error::new(std::io::ErrorKind::InvalidData, "mount path overflow")
            })?;
            let escape_start = index.checked_add(1).ok_or_else(|| {
                std::io::Error::new(std::io::ErrorKind::InvalidData, "mount path overflow")
            })?;
            if bytes[index] == b'\\' && escape_end <= bytes.len() {
                let digits = bytes.get(escape_start..escape_end).ok_or_else(|| {
                    std::io::Error::new(std::io::ErrorKind::InvalidData, "invalid mount escape")
                })?;
                if digits.iter().all(|digit| (b'0'..=b'7').contains(digit)) {
                    let value = u8::from_str_radix(
                        std::str::from_utf8(digits).map_err(std::io::Error::other)?,
                        8,
                    )
                    .map_err(std::io::Error::other)?;
                    decoded.push(value);
                    index = escape_end;
                    continue;
                }
            }
            decoded.push(bytes[index]);
            index = index.checked_add(1).ok_or_else(|| {
                std::io::Error::new(std::io::ErrorKind::InvalidData, "mount path overflow")
            })?;
        }
        if std::ffi::OsString::from_vec(decoded) == canonical.as_os_str() {

View on GitHub (pinned to affd8760f4)