wavetermdev/waveterm · error
procinfo: CreateToolhelp32Snapshot: %w
Error message
procinfo: CreateToolhelp32Snapshot: %w
What it means
MakeGlobalSnapshot opens a Win32 toolhelp snapshot of all processes via windows.CreateToolhelp32Snapshot; when the syscall fails this error wraps the underlying windows error. Without a snapshot no process data (ppid, threads, exe name) can be enumerated.
Source
Thrown at pkg/util/procinfo/procinfo_windows.go:49
}
// snapInfo holds the data collected in a single pass of CreateToolhelp32Snapshot.
type snapInfo struct {
ppid uint32
numThreads uint32
exeName string
}
// windowsSnapshot is the concrete type returned by MakeGlobalSnapshot on Windows.
type windowsSnapshot struct {
procs map[int32]*snapInfo
}
// MakeGlobalSnapshot enumerates all processes once via CreateToolhelp32Snapshot.
func MakeGlobalSnapshot() (any, error) {
snap, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0)
if err != nil {
return nil, fmt.Errorf("procinfo: CreateToolhelp32Snapshot: %w", err)
}
defer windows.CloseHandle(snap)
procs := make(map[int32]*snapInfo)
var entry windows.ProcessEntry32
entry.Size = uint32(unsafe.Sizeof(entry))
if err := windows.Process32First(snap, &entry); err != nil {
return nil, fmt.Errorf("procinfo: Process32First: %w", err)
}
for {
pid := int32(entry.ProcessID)
procs[pid] = &snapInfo{
ppid: entry.ParentProcessID,
numThreads: entry.Threads,
exeName: windows.UTF16ToString(entry.ExeFile[:]),
}View on GitHub (pinned to a4447c1563)
Solutions
- Read the wrapped %w error with errors.Is to identify the specific win32 error code
- Retry the call — transient failures can occur during heavy process create/destroy activity
- Run the process with sufficient privileges or adjust EDR/AV policy blocking snapshots
- Fall back to enumerating /proc-like data via other APIs (e.g. EnumProcesses) if snapshots are blocked
Example fix
// before
snap, err := procinfo.MakeGlobalSnapshot()
if err != nil {
return err
}
// after
snap, err := procinfo.MakeGlobalSnapshot()
if err != nil {
log.Printf("snapshot failed: %v; retrying once", err)
snap, err = procinfo.MakeGlobalSnapshot()
if err != nil {
return fmt.Errorf("cannot enumerate processes: %w", err)
}
} Defensive patterns
Strategy: retry
Try / catch
snap, err := procinfo.MakeGlobalSnapshot()
if err != nil {
var sysErr syscall.Errno
if errors.As(err, &sysErr) && sysErr == windows.ERROR_ACCESS_DENIED {
return fmt.Errorf("insufficient privileges to snapshot processes: %w", err)
}
time.Sleep(50 * time.Millisecond)
snap, err = procinfo.MakeGlobalSnapshot()
}
if err != nil { return err } Prevention
- Run with adequate privileges in hardened/EDR-heavy environments
- Retry once on failure — snapshot creation is occasionally transient
- Log the wrapped win32 error code for diagnosis
- Avoid calling during extreme process churn if possible
When it happens
Trigger: Calling MakeGlobalSnapshot when CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) fails — typically ERROR_ACCESS_DENIED from restrictive security software/policies, or when the calling process lacks sufficient privileges in hardened environments.
Common situations: Running under service accounts with stripped SeDebugPrivilege in locked-down environments; antivirus/EDR blocking toolhelp snapshots; extremely rare kernel resource exhaustion during process creation/destruction storms.
Related errors
- procinfo: Process32First: %w
- procinfo: Process32Next: %w
- --pid flag is not supported on Windows
- failed to create WSL command
- failed to start command: %w
AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01).
Data as JSON: /api/errors/935789626b7f4a57.
Report an issue: GitHub.