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

  1. Verify the PID still exists (e.g. `tasklist /FI "PID eq <pid>"`) before calling; if it exited, treat the info as unavailable.
  2. Re-run the lookup promptly after obtaining the PID to minimize the exit race.
  3. If the process is a child that just exited, inspect the parent process instead to learn what launched it.
  4. 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

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


AI-assisted analysis of pranshuparmar/witr@dc4fa1da82 (2026-09-01). Data as JSON: /api/errors/31261ec7f1c58cbf. Report an issue: GitHub.