{"record":{"id":"4b3716525cf75a2d","repo":"gastownhall/beads","slug":"procid-process-d-does-not-match-token-4b3716","errorCode":null,"errorMessage":"procid: process %d does not match token","messagePattern":"procid: process (.+?) does not match token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/procid/procid_windows.go","lineNumber":69,"sourceCode":"\t\t\treturn false, nil\n\t\t}\n\t\treturn false, err\n\t}\n\treturn current == tok, nil\n}\n\nfunc Open(pid int, tok Token) (*Handle, error) {\n\tprocess, err := openProcess(pid, windows.PROCESS_QUERY_LIMITED_INFORMATION|windows.PROCESS_TERMINATE)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"procid: open process %d: %w\", pid, err)\n\t}\n\tcurrent, err := tokenForProcess(process)\n\tif err != nil || current != tok {\n\t\t_ = windows.CloseHandle(process)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn nil, fmt.Errorf(\"procid: process %d does not match token\", pid)\n\t}\n\treturn &Handle{process: process, token: tok}, nil\n}\n\nfunc (h *Handle) Signal(os.Signal) error {\n\tif err := h.verify(); err != nil {\n\t\tif errors.Is(err, errProcessExited) {\n\t\t\t// The target exited on its own after Open; termination's goal is\n\t\t\t// already met.\n\t\t\treturn nil\n\t\t}\n\t\treturn err\n\t}\n\tif err := windows.TerminateProcess(h.process, 1); err != nil {\n\t\tif _, exitedErr := tokenForProcess(h.process); errors.Is(exitedErr, errProcessExited) {\n\t\t\treturn nil\n\t\t}\n\t\treturn fmt.Errorf(\"procid: terminate process: %w\", err)","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/procid/procid_windows.go#L51-L87","documentation":"procid.Open successfully opened the process, but tokenForProcess returned a creation-time token different from the supplied token, so Open refuses to return a handle. This is the PID-reuse guard: the PID now refers to a different process instance than the one the token was minted for.","triggerScenarios":"Calling Open(pid, tok) after the original process exited and Windows recycled the PID for a new process; passing a token captured from a different PID.","commonSituations":"Long-running daemons holding tokens across restarts where the target was restarted and got the same PID; tokens persisted to disk and reused much later; copying a token between hosts or records.","solutions":["Treat this as PID reuse: re-capture a fresh token with Capture(pid) before opening","Verify with Verify(pid, tok) before Open to detect mismatch without error noise","Persist the process creation time/token alongside the PID and refresh it whenever the target restarts","Never share tokens across machines or OS platforms (token format is windows-v1 creation time)"],"exampleFix":"// before\nh, err := procid.Open(pid, oldTok)\n// after\nif ok, _ := procid.Verify(pid, oldTok); !ok {\n    newTok, terr := procid.Capture(pid)\n    if terr != nil { return terr }\n    oldTok = newTok\n}\nh, err := procid.Open(pid, oldTok)","handlingStrategy":"validation","validationCode":"ok, err := procid.Verify(pid, tok)\nif err != nil {\n    return err\n}\nif !ok {\n    tok, err = procid.Capture(pid)\n    if err != nil {\n        return err\n    }\n}","typeGuard":"func tokenMatches(pid int, tok procid.Token) bool {\n    ok, err := procid.Verify(pid, tok)\n    return err == nil && ok\n}","tryCatchPattern":"h, err := procid.Open(pid, tok)\nif err != nil {\n    if strings.Contains(err.Error(), \"does not match token\") || tokenIsStale {\n        newTok, cerr := procid.Capture(pid)\n        if cerr != nil { return cerr }\n        h, err = procid.Open(pid, newTok)\n    }\n    if err != nil { return err }\n}","preventionTips":["Re-capture tokens after any target process restart","Do not reuse tokens captured on a different machine or OS","Treat 'does not match token' as PID reuse, never retry with the same token","Keep token lifetime tied to the target process lifecycle, not to config files"],"tags":["windows","process","pid-reuse","token-mismatch"],"backgroundTag":"pid-reuse-token-mismatch","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}