pranshuparmar/witr · warning
process %d not found in snapshot
Error message
process %d not found in snapshot
What it means
On Windows, when per-process detail cannot be read directly, witr falls back to a process snapshot (CreateToolhelp32Snapshot) to find the process's PPID and exe name. This error means the target PID was not present in the snapshot, so no information could be returned for it. It almost always means the process no longer exists.
Source
Thrown at internal/proc/peb_windows.go:310
uintptr(unsafe.Pointer(&size)),
)
if ret == 0 {
return ""
}
return syscall.UTF16ToString(buf[:size])
}
func getInfoFromSnapshot(pid int) (int, string, error) {
procs, err := enumerateProcesses()
if err != nil {
return 0, "", err
}
for _, p := range procs {
if p.PID == pid {
return p.PPID, p.Exe, nil
}
}
return 0, "", fmt.Errorf("process %d not found in snapshot", pid)
}
// processCommandLineInformation is the NtQueryInformationProcess class (60,
// Windows 8.1+) that returns a process's command line.
const processCommandLineInformation = 60
// windowsProcessCmdline returns a process's full command line via
// NtQueryInformationProcess(ProcessCommandLineInformation). The kernel copies
// the command line into our own buffer, so — unlike walking the PEB with
// ReadProcessMemory — there is no remote process-memory access: inaccessible or
// unusual processes return an error, and any anomaly degrades to an empty
// string rather than faulting. Safe to call across the whole process list.
func windowsProcessCmdline(pid int) string {
handle, err := syscall.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil {
return ""
}
defer syscall.CloseHandle(handle)View on GitHub (pinned to dc4fa1da82)
Solutions
- Verify the PID still exists (e.g. `tasklist /FI "PID eq <pid>"`) before calling; if it exited, treat the info as unavailable.
- Re-run the lookup promptly after obtaining the PID to minimize the exit race.
- If the process is a child that just exited, inspect the parent process instead to learn what launched it.
- Check for PID reuse: if a supervisor logged a different PID later, use the fresh PID.
Defensive patterns
Strategy: validation
Validate before calling
// verify the PID exists in a snapshot before detailed lookup
snap, _ := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
exists := false
// ... iterate Process32First/Next comparing ProcessID == pid
if !exists { return nil, fmt.Errorf("pid %d already exited", pid) } Try / catch
info, err := GetProcessDetailedInfo(pid)
if err != nil {
var nf *errType
if strings.Contains(err.Error(), "not found in snapshot") {
// process exited; treat as non-fatal and report 'process no longer exists'
}
} Prevention
- Call as soon as possible after obtaining the PID to avoid exit races
- Cache PIDs briefly, never long-term (PID reuse)
- Fall back to parent-process inspection when the target exited
When it happens
Trigger: GetProcessDetailedInfo (via getInfoFromSnapshot) called with a PID that has exited before or during the snapshot iteration, or a PID outside the snapshot's scope (e.g. a kernel/system-only PID filtered out by the enumeration).
Common situations: Inspecting short-lived processes (build tools, scripts) that vanish between spawning and inspection; racing a process that a supervisor just restarted with a new PID; stale PIDs cached by an upstream tool.
Related errors
- failed to read ProcessParameters struct
- process %d not found: %w
- process %d not found
- process %d not found: %w
- process %d not found
AI-assisted analysis of pranshuparmar/witr@dc4fa1da82 (2026-09-01).
Data as JSON: /api/errors/31261ec7f1c58cbf.
Report an issue: GitHub.