wavetermdev/waveterm · error

procinfo: invalid snapshot type

Error message

procinfo: invalid snapshot type

What it means

GetProcInfo type-asserts the snap parameter to *windowsSnapshot; if it is a non-nil value of any other type, this error is returned. It protects against passing foreign objects (e.g. a Linux snapshot type or a raw map) where the lookup would otherwise panic.

Source

Thrown at pkg/util/procinfo/procinfo_windows.go:88

				break
			}
			return nil, fmt.Errorf("procinfo: Process32Next: %w", err)
		}
	}

	return &windowsSnapshot{procs: procs}, nil
}

// GetProcInfo returns a ProcInfo for the given pid.
// snap must be a non-nil value returned by MakeGlobalSnapshot.
// Returns nil, nil if the pid is not present in the snapshot.
func GetProcInfo(_ context.Context, snap any, pid int32) (*ProcInfo, error) {
	if snap == nil {
		return nil, fmt.Errorf("procinfo: GetProcInfo requires a snapshot on windows")
	}
	ws, ok := snap.(*windowsSnapshot)
	if !ok {
		return nil, fmt.Errorf("procinfo: invalid snapshot type")
	}
	si, found := ws.procs[pid]
	if !found {
		return nil, ErrNotFound
	}

	info := &ProcInfo{
		Pid:        pid,
		Ppid:       int32(si.ppid),
		NumThreads: int32(si.numThreads),
		Command:    si.exeName,
		CpuUser:    -1,
		CpuSys:     -1,
		VmRSS:      -1,
	}

	handle, err := windows.OpenProcess(
		windows.PROCESS_QUERY_LIMITED_INFORMATION,

View on GitHub (pinned to a4447c1563)

Solutions

  1. Only pass values obtained from MakeGlobalSnapshot (same build/platform) into GetProcInfo
  2. Check the wrapped type at the call site before invoking
  3. Separate per-platform snapshot handling into typed code paths
  4. In tests, use the real MakeGlobalSnapshot or generate a proper *windowsSnapshot

Example fix

// before
info, err := procinfo.GetProcInfo(ctx, someGenericSnapshot, pid)
// after
if _, ok := someGenericSnapshot.(*procinfo.WindowsSnapshotLike); !ok && someGenericSnapshot != nil {
	someGenericSnapshot, err = procinfo.MakeGlobalSnapshot()
	if err != nil {
		return err
	}
}
info, err := procinfo.GetProcInfo(ctx, someGenericSnapshot, pid)
Defensive patterns

Strategy: type-guard

Validate before calling

if snap != nil {
	if _, ok := snap.(*procinfoSnapshot); !ok {
		snap, err = procinfo.MakeGlobalSnapshot()
	}
}

Type guard

func isWindowsSnapshot(snap any) bool {
	// snap is typed any; assert against the value returned by MakeGlobalSnapshot
	return snap != nil && fmt.Sprintf("%T", snap) == "*procinfo.windowsSnapshot"
}

Try / catch

info, err := procinfo.GetProcInfo(ctx, snap, pid)
if err != nil {
	if strings.Contains(err.Error(), "invalid snapshot type") {
		return fmt.Errorf("snap must come from MakeGlobalSnapshot, got %T", snap)
	}
	if errors.Is(err, procinfo.ErrNotFound) {
		return nil // pid absent from snapshot
	}
	return err
}

Prevention

When it happens

Trigger: Calling GetProcInfo with a non-nil snap that was not produced by MakeGlobalSnapshot on Windows — e.g. a snapshot from a different platform build, a mock in tests, or an `any` variable holding the wrong concrete type.

Common situations: Cross-platform code paths storing heterogeneous snapshot types in one `any` field; test doubles that don't match the internal snapshot type; refactors that swap snapshot implementations without updating call sites.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/babf2f4bcbb4ef6c. Report an issue: GitHub.