gastownhall/beads · error
procid: get process exit code: %w
Error message
procid: get process exit code: %w
What it means
tokenForProcess calls windows.GetExitCodeProcess to check liveness before minting a token; if that Win32 call fails the error is wrapped with this message. It is reachable from Capture, Verify, Open, Signal and Handle.verify, so any of those public APIs can surface it.
Source
Thrown at internal/procid/procid_windows.go:127
return err
}
if current != h.token {
return fmt.Errorf("procid: process no longer matches token")
}
return nil
}
func openProcess(pid int, access uint32) (windows.Handle, error) {
return windows.OpenProcess(access, false, uint32(pid))
}
func tokenForProcess(process windows.Handle) (Token, error) {
// An open handle keeps a terminated process's PID resolvable and its
// creation time readable, so check liveness explicitly before minting a
// token for it.
var code uint32
if err := windows.GetExitCodeProcess(process, &code); err != nil {
return "", fmt.Errorf("procid: get process exit code: %w", err)
}
if code != stillActive {
return "", errProcessExited
}
var created, exited, kernel, user windows.Filetime
if err := windows.GetProcessTimes(process, &created, &exited, &kernel, &user); err != nil {
return "", fmt.Errorf("procid: get process times: %w", err)
}
value := uint64(created.HighDateTime)<<32 | uint64(created.LowDateTime)
return Token("windows-v1:" + strconv.FormatUint(value, 10)), nil
}
// IsProcessGone reports whether err means the referenced process no longer
// exists.
func IsProcessGone(err error) bool {
return errors.Is(err, windows.ERROR_INVALID_PARAMETER) ||
errors.Is(err, errProcessExited)
}View on GitHub (pinned to 71377f2769)
Solutions
- Ensure the process handle was opened with PROCESS_QUERY_LIMITED_INFORMATION (always use procid.Open/Capture rather than raw OpenProcess)
- Check errors.Is(err, windows.ERROR_ACCESS_DENIED) and elevate if needed
- Avoid sharing/invalidating the underlying handle outside procid; don't Close handles concurrently with Signal/Verify
- If the process is gone, prefer procid.IsProcessGone / errProcessExited handling over treating this as a hard failure
Example fix
// before
proc, _ := windows.OpenProcess(windows.SYNCHRONIZE, false, uint32(pid))
tok, err := procid.Verify(pid, known) // unrelated handle rights cause query failures elsewhere
// after
proc, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil { return err } Defensive patterns
Strategy: validation
Validate before calling
// Ensure handles come from procid APIs that request the right access
proc, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil {
return fmt.Errorf("cannot query pid %d: %w", pid, err)
}
_ = windows.CloseHandle(proc) Type guard
func canQuery(pid int) bool {
h, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, uint32(pid))
if err != nil { return false }
_ = windows.CloseHandle(h)
return true
} Try / catch
tok, err := procid.Capture(pid)
if err != nil {
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
return nil // skip unqueryable process
}
return err
} Prevention
- Always obtain process handles through procid.Capture/Open, which request the required access
- Do not share raw windows.Handle values with code that may close them
- Check access rights early rather than at token-mint time
- Run token-minting code as the same user as the target processes where possible
When it happens
Trigger: Calling any procid API with a handle that lacks PROCESS_QUERY_LIMITED_INFORMATION access, or a handle that has become invalid between Open and the token query.
Common situations: Constructing handles with narrower access rights than the library requires; handle closed concurrently while another goroutine queries it; mixing procid with other code that closes raw windows.Handle values.
Related errors
- procid: terminate process: %w
- procid: get process times: %w
- failed to create .beads directory: %v Windows Controlled Fo
- finding process %d: %w
- sending SIGTERM to PID %d: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/5330de5b3452bf7d.
Report an issue: GitHub.