gastownhall/beads · warning

finding process %d: %w

Error message

finding process %d: %w

What it means

The Windows variant of gracefulStop wraps os.FindProcess(pid) failures as "finding process %d: %w". On Windows FindProcess opens a real handle, so it fails immediately when the PID is dead or invalid. Data safety comes from FlushRunningSet in StopWithForce, not from this signal, so the error means bd could not even reach the process to kill it.

Source

Thrown at internal/doltserver/doltserver_windows.go:123

func isProcessAlive(pid int) bool {
	h, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))
	if err != nil {
		return false
	}
	defer func() { _ = windows.CloseHandle(h) }()

	status, err := windows.WaitForSingleObject(h, 0)
	return err == nil && status == uint32(windows.WAIT_TIMEOUT)
}

// gracefulStop terminates a process on Windows. Uses TerminateProcess (hard kill)
// directly. Data safety comes from FlushWorkingSet which runs in StopWithForce
// before calling gracefulStop. The Unix SIGTERM is a courtesy; the real protection
// is the flush.
func gracefulStop(pid int, timeout time.Duration) error {
	process, err := os.FindProcess(pid)
	if err != nil {
		return fmt.Errorf("finding process %d: %w", pid, err)
	}
	_ = process.Kill()
	time.Sleep(500 * time.Millisecond)
	return nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Re-read server metadata to confirm the PID is current; delete stale metadata if the server is gone.
  2. Treat a not-found PID as 'server already stopped' and continue startup — the flush already happened.
  3. Check the running dolt-server process list (tasklist) to find the real PID if one is truly alive.
  4. If the port is still occupied by another process, reclaim by port rather than by stored PID.
Defensive patterns

Strategy: fallback

Validate before calling

if pid <= 0 {
    // stale metadata; skip stop entirely
    return nil
}
// Windows: FindProcess fails for dead PIDs, so probe first
if _, err := os.FindProcess(pid); err != nil {
    return nil // already gone
}

Type guard

func pidResolvable(pid int) bool {
    if pid <= 0 { return false }
    _, err := os.FindProcess(pid)
    return err == nil
}

Try / catch

err := gracefulStop(pid, timeout)
if err != nil {
    // FlushWorkingSet already ran; treat as best-effort
    log.Printf("could not stop pid %d (may already be dead): %v", pid, err)
    return nil
}

Prevention

When it happens

Trigger: StopWithForce on Windows calls gracefulStop with a PID that no longer exists (server already exited), a PID reused by another process that then closed, or pid <= 0 from corrupted server metadata.

Common situations: Stale .dolt/server metadata after a crash or reboot; PID recycling assigning the old number to a short-lived process; bd run under a different user without handle-open rights on the target process.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/e9b4dd8523885b9a. Report an issue: GitHub.