ClementTsang/bottom · error
missing state
Error message
missing state
What it means
After splitting the stat remainder into whitespace-separated fields, the parser takes the first field as the process state and requires at least one character from it (the state is a single letter like R, S, Z). An empty first field means there are no stat fields at all, so the library raises this error.
Solutions
- Retry reading the stat file once; truncation due to a dying process is usually transient.
- Skip the entry during enumeration, treating it as a process that disappeared mid-scan.
- Fix test fixtures to include a state letter immediately after the closing paren, e.g. '(bash) S 1 ...'.
Example fix
// before
let state = next_part(&mut rest)?.chars().next().unwrap();
// after
let proc = match Process::from_file(&stat_path) {
Ok(p) => Some(p),
Err(_) => None, // treat unreadable stat as process-gone
}; Defensive patterns
Strategy: validation
Validate before calling
fn has_state_field(line: &str) -> bool {
line.rsplit_once(") ")
.map(|(_, rest)| !rest.trim().is_empty())
.unwrap_or(false)
}
if !has_state_field(&line) { skip_entry(); } Type guard
fn first_field(rest: &str) -> Option<char> {
rest.split(' ').next()?.chars().next()
} Try / catch
match Process::from_file(path) {
Err(e) if e.to_string().contains("missing state") => None,
Err(e) => return Err(e.into()),
Ok(p) => Some(p),
} Prevention
- Validate that stat content has fields after the comm before parsing
- Skip rather than fail when enumerating all processes
- Ensure test fixtures include a state letter (R/S/D/Z/...) after the comm
When it happens
Trigger: Process::from_file is given a stat line whose post-comm remainder is empty or whitespace-only, so the state field cannot be extracted — typically a truncated read or a file containing only '(comm)' with nothing after it.
Common situations: Racing with process exit so the stat content is cut off after the comm field; malformed synthetic test input missing the state field; unusual procfs implementations that emit incomplete records.
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
- start paren missing
- stat string is malformed
- PID for was not found
- Unexpected 'ps' output
- missing device
AI-assisted analysis of ClementTsang/bottom@b77d317502 (2026-09-07).
Data as JSON: /api/errors/cee9d869ff123d60.
Report an issue: GitHub.
Appendix: source
Thrown at src/collection/processes/linux/process.rs:116
// an rsplit over the full string.
//
// Sources/discussion:
// - https://man.archlinux.org/man/proc_pid_stat.5.en
// - https://stackoverflow.com/questions/23534263/what-is-the-maximum-allowed-limit-on-the-length-of-a-process-name#comment138697304_23534499
// - https://elixir.bootlin.com/linux/v7.1.3/source/fs/proc/array.c#L100
// - https://github.com/ClementTsang/bottom/pull/2163#issuecomment-5017857303
let (comm, rest) = line[start_paren + 1..]
.rsplit_once(") ")
.ok_or_else(|| anyhow!("stat string is malformed"))?;
(comm.to_string(), rest)
};
let mut rest = rest.split(' ');
let state = next_part(&mut rest)?
.chars()
.next()
.ok_or_else(|| anyhow!("missing state"))?;
let ppid: Pid = next_part(&mut rest)?.parse()?;
// Skip 4 fields (pgrp, session, tty_nr, tpgid)
let mut rest = rest.skip(4);
// read flags for kernel thread (PF_KTHREAD from include/linux/sched.h)
let flags: u32 = next_part(&mut rest)?.parse()?;
let is_kernel_thread: bool = flags & 0x00200000 != 0;
// Skip 4 fields (minflt, cminflt, majflt, cmajflt)
let mut rest = rest.skip(4);
let utime: u64 = next_part(&mut rest)?.parse()?;
let stime: u64 = next_part(&mut rest)?.parse()?;
// cutime
let _ = next_part(&mut rest)?;
// cstime
let _ = next_part(&mut rest)?;View on GitHub (pinned to b77d317502)