{"record":{"id":"43d82cf6bc7be907","repo":"ClementTsang/bottom","slug":"failed-to-get-priority-class-for-process-with-pid","errorCode":null,"errorMessage":"Failed to get priority class for process with PID {pid}","messagePattern":"Failed to get priority class for process with PID (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/collection/processes/windows.rs","lineNumber":30,"sourceCode":"use super::{ProcessHarvest, process_status_str};\nuse crate::collection::{DataCollector, error::CollectionResult};\n\n/// See [here](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getpriorityclass)\n/// for more information on the core Windows API being called and the meaning of\n/// the priorities, as well as the access rights needed.\nfn get_priority(pid: u32) -> anyhow::Result<i32> {\n    // SAFETY: We check validity of each step and bail on errors. We also close\n    // the handle.\n    unsafe {\n        let process_handle: HANDLE = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid)?;\n        if process_handle.is_invalid() {\n            bail!(\"Failed to open process with PID {pid} to get priority class\");\n        }\n\n        // From docs: \"If the function fails, the return value is zero.\"\n        let priority = GetPriorityClass(process_handle);\n        if priority == 0 {\n            bail!(\"Failed to get priority class for process with PID {pid}\");\n        }\n\n        let handle_result = CloseHandle(process_handle);\n        if let Err(err) = handle_result {\n            bail!(err);\n        }\n\n        Ok(priority as i32)\n    }\n}\n\n// TODO: There's a lot of shared code with this and the unix impl.\npub fn sysinfo_process_data(\n    collector: &mut DataCollector,\n) -> CollectionResult<Vec<ProcessHarvest>> {\n    let sys = &collector.sys.system;\n    let users = &collector.sys.users;\n    let use_current_cpu_total = collector.use_current_cpu_total;","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/ClementTsang/bottom/blob/b77d3175028849824e987c35177e8f61450d72e7/src/collection/processes/windows.rs#L12-L48","documentation":"After opening the process handle successfully, get_priority calls GetPriorityClass, which per Microsoft docs returns zero on failure, and the library bails. The handle was valid, but the kernel could not report the priority class. The handle is leaked at this bail point (CloseHandle happens after the check).","triggerScenarios":"GetPriorityClass(process_handle) returns 0 — the process exited between OpenProcess and the query (handle now points to a dead process), or an internal query failure on a terminating process.","commonSituations":"Rapid process churn: short-lived processes dying in the microseconds between opening the handle and querying the class; batch-collecting priority for every PID on a busy system.","solutions":["Skip the PID — exit races are expected in process monitoring; retry on the next collection cycle","Close the handle in all paths (use a guard/defer pattern) so the bail does not leak the handle","Re-fetch a fresh process list instead of reusing stale PIDs from an earlier snapshot","Log at debug level rather than erroring the entire sysinfo_process_data collection"],"exampleFix":"// before\nlet priority = GetPriorityClass(process_handle);\nif priority == 0 {\n    bail!(\"Failed to get priority class for process with PID {pid}\");\n}\n// after\nlet priority = GetPriorityClass(process_handle);\nlet _ = CloseHandle(process_handle); // always release\nif priority == 0 {\n    return Ok(0); // process exited mid-query; skip\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match get_priority(pid) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"priority class\") => 0, // exit race\n    Err(e) => { log::debug!(\"{e}\"); 0 }\n}","preventionTips":["Close the process handle on every path (RAII guard) to avoid leaks on bail","Treat GetPriorityClass == 0 as 'process exited mid-query' and skip","Re-query on the next collection cycle instead of retrying immediately"],"tags":["windows","processes","priority","race-condition"],"backgroundTag":"api-error-response","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"}