{"record":{"id":"cee9d869ff123d60","repo":"ClementTsang/bottom","slug":"missing-state","errorCode":null,"errorMessage":"missing state","messagePattern":"missing state","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/collection/processes/linux/process.rs","lineNumber":116,"sourceCode":"            // an rsplit over the full string.\n            //\n            // Sources/discussion:\n            // - https://man.archlinux.org/man/proc_pid_stat.5.en\n            // - https://stackoverflow.com/questions/23534263/what-is-the-maximum-allowed-limit-on-the-length-of-a-process-name#comment138697304_23534499\n            // - https://elixir.bootlin.com/linux/v7.1.3/source/fs/proc/array.c#L100\n            // - https://github.com/ClementTsang/bottom/pull/2163#issuecomment-5017857303\n            let (comm, rest) = line[start_paren + 1..]\n                .rsplit_once(\") \")\n                .ok_or_else(|| anyhow!(\"stat string is malformed\"))?;\n\n            (comm.to_string(), rest)\n        };\n\n        let mut rest = rest.split(' ');\n        let state = next_part(&mut rest)?\n            .chars()\n            .next()\n            .ok_or_else(|| anyhow!(\"missing state\"))?;\n        let ppid: Pid = next_part(&mut rest)?.parse()?;\n\n        // Skip 4 fields (pgrp, session, tty_nr, tpgid)\n        let mut rest = rest.skip(4);\n\n        // read flags for kernel thread (PF_KTHREAD from include/linux/sched.h)\n        let flags: u32 = next_part(&mut rest)?.parse()?;\n        let is_kernel_thread: bool = flags & 0x00200000 != 0;\n\n        // Skip 4 fields (minflt, cminflt, majflt, cmajflt)\n        let mut rest = rest.skip(4);\n        let utime: u64 = next_part(&mut rest)?.parse()?;\n        let stime: u64 = next_part(&mut rest)?.parse()?;\n\n        // cutime\n        let _ = next_part(&mut rest)?;\n        // cstime\n        let _ = next_part(&mut rest)?;","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/ClementTsang/bottom/blob/b77d3175028849824e987c35177e8f61450d72e7/src/collection/processes/linux/process.rs#L98-L134","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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 ...'."],"exampleFix":"// before\nlet state = next_part(&mut rest)?.chars().next().unwrap();\n// after\nlet proc = match Process::from_file(&stat_path) {\n    Ok(p) => Some(p),\n    Err(_) => None, // treat unreadable stat as process-gone\n};","handlingStrategy":"validation","validationCode":"fn has_state_field(line: &str) -> bool {\n    line.rsplit_once(\") \")\n        .map(|(_, rest)| !rest.trim().is_empty())\n        .unwrap_or(false)\n}\nif !has_state_field(&line) { skip_entry(); }","typeGuard":"fn first_field(rest: &str) -> Option<char> {\n    rest.split(' ').next()?.chars().next()\n}","tryCatchPattern":"match Process::from_file(path) {\n    Err(e) if e.to_string().contains(\"missing state\") => None,\n    Err(e) => return Err(e.into()),\n    Ok(p) => Some(p),\n}","preventionTips":["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"],"tags":["linux","procfs","parsing","processes"],"backgroundTag":"invalid-argument-format","analyzedSha":"b77d3175028849824e987c35177e8f61450d72e7","analyzedAt":"2026-09-07T14:53:21.246Z","contentChangedAt":"2026-09-07T14:53:21.246Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}