{"record":{"id":"9c05ac6d1340d491","repo":"gastownhall/beads","slug":"procid-get-process-times-w","errorCode":null,"errorMessage":"procid: get process times: %w","messagePattern":"procid: get process times: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/procid/procid_windows.go","lineNumber":134,"sourceCode":"\nfunc openProcess(pid int, access uint32) (windows.Handle, error) {\n\treturn windows.OpenProcess(access, false, uint32(pid))\n}\n\nfunc tokenForProcess(process windows.Handle) (Token, error) {\n\t// An open handle keeps a terminated process's PID resolvable and its\n\t// creation time readable, so check liveness explicitly before minting a\n\t// token for it.\n\tvar code uint32\n\tif err := windows.GetExitCodeProcess(process, &code); err != nil {\n\t\treturn \"\", fmt.Errorf(\"procid: get process exit code: %w\", err)\n\t}\n\tif code != stillActive {\n\t\treturn \"\", errProcessExited\n\t}\n\tvar created, exited, kernel, user windows.Filetime\n\tif err := windows.GetProcessTimes(process, &created, &exited, &kernel, &user); err != nil {\n\t\treturn \"\", fmt.Errorf(\"procid: get process times: %w\", err)\n\t}\n\tvalue := uint64(created.HighDateTime)<<32 | uint64(created.LowDateTime)\n\treturn Token(\"windows-v1:\" + strconv.FormatUint(value, 10)), nil\n}\n\n// IsProcessGone reports whether err means the referenced process no longer\n// exists.\nfunc IsProcessGone(err error) bool {\n\treturn errors.Is(err, windows.ERROR_INVALID_PARAMETER) ||\n\t\terrors.Is(err, errProcessExited)\n}\n","sourceCodeStart":116,"sourceCodeEnd":146,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/procid/procid_windows.go#L116-L146","documentation":"After confirming the process is still active, tokenForProcess reads the process creation time via windows.GetProcessTimes to build a unique, PID-reuse-resistant token. If GetProcessTimes fails, the error is wrapped and propagated to whichever public API (Capture/Verify/Open/Signal/verify) initiated the token mint.","triggerScenarios":"GetProcessTimes failing on a freshly opened handle — access denied on protected/system processes, or the handle was opened without query rights.","commonSituations":"Capturing tokens for SYSTEM or protected processes from a non-elevated daemon; handle rights reduced by third-party code; race where the handle was closed concurrently.","solutions":["Verify the handle has PROCESS_QUERY_LIMITED_INFORMATION (procid.Capture already requests it)","Check errors.Is(err, windows.ERROR_ACCESS_DENIED); run elevated or skip processes you cannot query","Retry the Capture once after a short delay in case of transient handle invalidation","Skip token capture for processes outside your ownership boundary instead of failing the whole batch"],"exampleFix":"// before\ntok, err := procid.Capture(pid)\nif err != nil { return err }\n// after\ntok, err := procid.Capture(pid)\nif err != nil {\n    if errors.Is(err, windows.ERROR_ACCESS_DENIED) {\n        return nil // cannot token-capture protected process; skip\n    }\n    return err\n}","handlingStrategy":"retry","validationCode":"if !canQuery(pid) {\n    return nil // cannot read process times; skip capture\n}","typeGuard":"func tokenCapturable(pid int) bool {\n    h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))\n    if err != nil { return false }\n    _ = windows.CloseHandle(h)\n    return true\n}","tryCatchPattern":"var tok procid.Token\nvar err error\nfor i := 0; i < 2; i++ {\n    tok, err = procid.Capture(pid)\n    if err == nil || procid.IsProcessGone(err) || errors.Is(err, windows.ERROR_ACCESS_DENIED) {\n        break\n    }\n    time.Sleep(50 * time.Millisecond)\n}","preventionTips":["Capture tokens for processes you own; skip SYSTEM/protected processes up front","Retry once on transient handle failures before giving up","Classify errors with procid.IsProcessGone and ERROR_ACCESS_DENIED instead of retrying blindly","Keep procid library and golang.org/x/sys versions current"],"tags":["windows","process","token","permissions"],"backgroundTag":"process-query-access-denied","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}