{"record":{"id":"6fd10f699dbc950c","repo":"gastownhall/beads","slug":"procid-process-d-still-matches-token-after-fatal","errorCode":null,"errorMessage":"procid: process %d still matches token after fatal signal and %s re-check","messagePattern":"procid: process (.+?) still matches token after fatal signal and (.+?) re-check","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/procid/procid_darwin.go","lineNumber":97,"sourceCode":"\t}\n\tif !match {\n\t\treturn fmt.Errorf(\"procid: process %d no longer matches token\", h.pid)\n\t}\n\treturn nil\n}\n\nfunc (h *Handle) confirmFatalSignal() error {\n\tdeadline := time.Now().Add(fallbackSignalConfirmTimeout)\n\tfor {\n\t\tmatch, err := Verify(h.pid, h.token)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tif !match {\n\t\t\treturn nil\n\t\t}\n\t\tif time.Now().After(deadline) {\n\t\t\treturn fmt.Errorf(\n\t\t\t\t\"procid: process %d still matches token after fatal signal and %s re-check\",\n\t\t\t\th.pid,\n\t\t\t\tfallbackSignalConfirmTimeout,\n\t\t\t)\n\t\t}\n\t\ttime.Sleep(10 * time.Millisecond)\n\t}\n}\n\nfunc isFatalSignal(sig syscall.Signal) bool {\n\treturn sig == syscall.SIGKILL || sig == syscall.SIGTERM\n}\n\nfunc (h *Handle) Kill() error { return h.Signal(syscall.SIGKILL) }\n\nfunc (h *Handle) Close() error { return nil }\n\n// IsProcessGone reports whether err means the referenced process no longer","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/procid/procid_darwin.go#L79-L115","documentation":"After sending a fatal signal (SIGKILL/SIGTERM) on darwin, Handle.Signal polls Verify for up to fallbackSignalConfirmTimeout (2s) to confirm the process actually died. If the process still matches the token after the timeout, the library reports that the kill did not take effect within the confirmation window.","triggerScenarios":"Handle.Signal(SIGKILL)/Kill() (or SIGTERM) where the process survives the full 2-second confirmation loop while still matching its token — e.g. SIGTERM trapped/ignored by the target, or the system is heavily loaded so exit is delayed.","commonSituations":"Applications installing a SIGTERM handler that blocks shutdown; processes stuck in uninterruptible work that delay reaping; heavily loaded CI machines; sending SIGTERM (treated as fatal here) to a process that handles it gracefully and takes longer than 2s to exit.","solutions":["Send SIGKILL instead of SIGTERM if the target may trap SIGTERM (SIGKILL cannot be handled).","Wait and re-check: poll Verify yourself after returning, since the process may exit just after the 2s window.","Increase tolerance in your caller: retry the kill after this error before treating it as a hard failure.","Investigate the target for stuck states (D-state, blocked handlers) if it survives SIGKILL for more than 2 seconds."],"exampleFix":"// before\nif err := handle.Kill(); err != nil {\n    return fmt.Errorf(\"hard failure: %w\", err)\n}\n// after\nif err := handle.Kill(); err != nil {\n    if strings.Contains(err.Error(), \"still matches token\") {\n        time.Sleep(500 * time.Millisecond)\n        _ = handle.Kill() // SIGKILL retry; then treat as gone if token changed\n    }\n}","handlingStrategy":"retry","validationCode":"// No pre-call validation possible; target may trap SIGTERM. Prefer SIGKILL if survival is unacceptable:\n// h.Kill() instead of h.Signal(syscall.SIGTERM)","typeGuard":null,"tryCatchPattern":"if err := h.Kill(); err != nil {\n    if strings.Contains(err.Error(), \"still matches token\") {\n        time.Sleep(2 * time.Second)\n        return h.Kill() // one retry; process may have needed longer to exit\n    }\n    return err\n}","preventionTips":["Use SIGKILL for targets that must die and cannot be trusted to honor SIGTERM","Set SIGTERM handlers in your own workers to exit well within 2 seconds","After this error, poll procid.Verify before declaring the kill failed","Watch for D-state/stuck processes if SIGKILL also times out"],"tags":["signal","timeout","darwin","sigterm","shutdown"],"backgroundTag":"process-kill-timeout","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}