rustfs/rustfs · warning · std::io::Error

failed to parse '{token}' as u64: {e}

Error message

failed to parse '{token}' as u64: {e}

What it means

read_stat (crates/utils/src/os/linux.rs:364) splits the first line of a sysfs stats file on whitespace and parses every token as u64; any non-numeric token returns InvalidData naming the token. The /sys/dev/block/*/stat ABI is all-numeric, so this fires when the file's layout differs from expectations or the path points at the wrong file.

Source

Thrown at crates/utils/src/os/linux.rs:364

fn read_stat(file_name: &str) -> std::io::Result<Vec<u64>> {
    // Open file
    let path = Path::new(file_name);
    let file = File::open(path)?;

    // Create a BufReader
    let reader = io::BufReader::new(file);

    // Read first line
    let mut stats = Vec::new();
    if let Some(line) = reader.lines().next() {
        let line = line?;
        // Split line and parse as u64
        // https://rust-lang.github.io/rust-clippy/master/index.html#trim_split_whitespace
        for token in line.split_whitespace() {
            let ui64: u64 = token
                .parse()
                .map_err(|e| Error::new(ErrorKind::InvalidData, format!("failed to parse '{token}' as u64: {e}")))?;
            stats.push(ui64);
        }
    }

    Ok(stats)
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::tempdir;

    #[test]
    fn normalize_partition_device_to_parent_disk() {
        let dir = tempdir().unwrap();
        let block = dir.path().join("block");
        let disk = block.join("nvme0n1");
        let partition = disk.join("nvme0n1p1");

View on GitHub (pinned to 35af688cd9)

Solutions

  1. Manually inspect the file's first line and compare it with the expected numeric layout.
  2. Verify the major:minor to path mapping (/sys/dev/block/MAJ:MIN/stat) is current — device numbers change across reboots or udev re-enumeration.
  3. Skip non-numeric columns defensively if only specific indices are consumed.
Defensive patterns

Strategy: fallback

Validate before calling

let first = std::fs::read_to_string(path)?.lines().next().unwrap_or_default();
let all_numeric = first.split_whitespace().all(|t| t.parse::<u64>().is_ok());
if !all_numeric { /* skip or trim non-numeric columns */ }

Try / catch

match read_stat(path) {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => { warn!("unparseable stats file: {e}"); vec![] }
    r => r.unwrap_or_default(),
}

Prevention

When it happens

Trigger: A stats line containing a non-numeric field — a device-name column or '-' placeholder where a counter should be — or calling read_stat on a file whose format is not a plain numeric row.

Common situations: Kernel-version differences in sysfs layout; a stale major:minor mapping after device changes; virtualized environments exposing unusual sysfs content.

Understand the failure class

Related errors


AI-assisted analysis of rustfs/rustfs@35af688cd9 (2026-08-20). Data as JSON: /api/errors/47761fb10b649830. Report an issue: GitHub.