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
- Manually inspect the file's first line and compare it with the expected numeric layout.
- Verify the major:minor to path mapping (/sys/dev/block/MAJ:MIN/stat) is current — device numbers change across reboots or udev re-enumeration.
- 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
- Pin the expected sysfs field layout per kernel version instead of assuming one shape.
- Re-resolve major:minor to a sysfs path after device changes rather than caching it.
- Log the offending token so layout changes are diagnosable from logs.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- found invalid format while reading {stats_file}
- {0}
- CSVParsingError
- JSONParsingError
- ParquetParsingError
AI-assisted analysis of rustfs/rustfs@35af688cd9 (2026-08-20).
Data as JSON: /api/errors/47761fb10b649830.
Report an issue: GitHub.