{"record":{"id":"e9b4dd8523885b9a","repo":"gastownhall/beads","slug":"finding-process-d-w-e9b4dd","errorCode":null,"errorMessage":"finding process %d: %w","messagePattern":"finding process (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/doltserver/doltserver_windows.go","lineNumber":123,"sourceCode":"func isProcessAlive(pid int) bool {\n\th, err := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))\n\tif err != nil {\n\t\treturn false\n\t}\n\tdefer func() { _ = windows.CloseHandle(h) }()\n\n\tstatus, err := windows.WaitForSingleObject(h, 0)\n\treturn err == nil && status == uint32(windows.WAIT_TIMEOUT)\n}\n\n// gracefulStop terminates a process on Windows. Uses TerminateProcess (hard kill)\n// directly. Data safety comes from FlushWorkingSet which runs in StopWithForce\n// before calling gracefulStop. The Unix SIGTERM is a courtesy; the real protection\n// is the flush.\nfunc gracefulStop(pid int, timeout time.Duration) error {\n\tprocess, err := os.FindProcess(pid)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"finding process %d: %w\", pid, err)\n\t}\n\t_ = process.Kill()\n\ttime.Sleep(500 * time.Millisecond)\n\treturn nil\n}\n","sourceCodeStart":105,"sourceCodeEnd":129,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/doltserver/doltserver_windows.go#L105-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-read server metadata to confirm the PID is current; delete stale metadata if the server is gone.","Treat a not-found PID as 'server already stopped' and continue startup — the flush already happened.","Check the running dolt-server process list (tasklist) to find the real PID if one is truly alive.","If the port is still occupied by another process, reclaim by port rather than by stored PID."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"if pid <= 0 {\n    // stale metadata; skip stop entirely\n    return nil\n}\n// Windows: FindProcess fails for dead PIDs, so probe first\nif _, err := os.FindProcess(pid); err != nil {\n    return nil // already gone\n}","typeGuard":"func pidResolvable(pid int) bool {\n    if pid <= 0 { return false }\n    _, err := os.FindProcess(pid)\n    return err == nil\n}","tryCatchPattern":"err := gracefulStop(pid, timeout)\nif err != nil {\n    // FlushWorkingSet already ran; treat as best-effort\n    log.Printf(\"could not stop pid %d (may already be dead): %v\", pid, err)\n    return nil\n}","preventionTips":["Delete stale server metadata instead of trusting its PID","Verify the process exists via tasklist before killing","Remember Windows FindProcess fails on dead PIDs (unlike Unix)","Rely on FlushWorkingSet for data safety, not the kill"],"tags":["process","windows","graceful-shutdown","stale-metadata"],"backgroundTag":"process-lookup-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}