{"record":{"id":"71fe7d4909e0714a","repo":"ClementTsang/bottom","slug":"failed-to-open-process-with-pid-pid-to-get-prior","errorCode":null,"errorMessage":"Failed to open process with PID {pid} to get priority class","messagePattern":"Failed to open process with PID (.+?) to get priority class","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/collection/processes/windows.rs","lineNumber":24,"sourceCode":"use itertools::Itertools;\nuse windows::Win32::{\n    Foundation::{CloseHandle, HANDLE},\n    System::Threading::{GetPriorityClass, OpenProcess, PROCESS_QUERY_LIMITED_INFORMATION},\n};\n\nuse 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.","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/ClementTsang/bottom/blob/b77d3175028849824e987c35177e8f61450d72e7/src/collection/processes/windows.rs#L6-L42","documentation":"get_priority opens a target process with OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION) and bails if the returned handle is invalid. Without a valid process handle the library cannot query the priority class via GetPriorityClass. This reflects the OS refusing (or being unable) to grant even limited query access to the PID.","triggerScenarios":"OpenProcess returns an invalid (NULL) handle — the PID no longer exists (ERROR_INVALID_PARAMETER), access is denied (ERROR_ACCESS_DENIED for protected/system processes), or the PID value is malformed.","commonSituations":"Querying PIDs captured in an earlier snapshot after the processes exited; inspecting protected processes (antivirus, system-critical, PPL processes) that block even PROCESS_QUERY_LIMITED_INFORMATION; passing 0 or kernel PIDs.","solutions":["Treat as benign for a process monitor: skip the PID and continue enumerating","Verify the PID is still alive before calling (e.g. OpenProcess itself, or a fresh process list)","Check the OS error from the preceding OpenProcess `?` to distinguish access-denied from nonexistent PID","Run elevated only if you genuinely need data on protected/system processes"],"exampleFix":"// before\nlet process_handle: HANDLE = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid)?;\nif process_handle.is_invalid() {\n    bail!(\"Failed to open process with PID {pid} to get priority class\");\n}\n// after\nlet process_handle: HANDLE = match OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid) {\n    Ok(h) if !h.is_invalid() => h,\n    _ => return Ok(0), // or skip: process gone / protected\n};","handlingStrategy":"validation","validationCode":"// confirm the PID exists in a fresh process snapshot before querying priority\nfn pid_in_snapshot(pid: u32, snapshot: &[u32]) -> bool { snapshot.contains(&pid) }","typeGuard":"fn handle_valid(h: HANDLE) -> bool { !h.is_invalid() }","tryCatchPattern":"match get_priority(pid) {\n    Ok(p) => p,\n    Err(e) if e.to_string().contains(\"Failed to open process\") => 0, // skip\n    Err(e) => { log::debug!(\"{e}\"); 0 }\n}","preventionTips":["Always derive PIDs from a freshly taken process list","Expect access-denied on protected/system processes and skip them","Never pass PID 0 or system PIDs to priority queries"],"tags":["windows","processes","handle","permissions"],"backgroundTag":"permission-denied","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"}