[Bug] Keychain race condition causes DELETE of canonical credentials entry on concurrent token refresh with stale tokens

Resolved 💬 3 comments Opened May 8, 2026 by drjagan Closed May 12, 2026

Bug Description
Subject: 2.1.118 keychain-race fix is incomplete — DELETE still observed on
2.1.133
Version: 2.1.133 (latest as of 08-05-2026)
OS: macOS 25.4.0 (arm64), Max plan, OAuth (oat01-...)
The 2.1.118 fix ("Fixed macOS keychain race where a concurrent MCP token
refresh could overwrite a freshly-refreshed OAuth token") narrowed one race path. A
second path still wipes the canonical Claude Code-credentials Keychain entry on
2.1.133.
DETERMINISTIC REPRO (4 captures by automated polling watcher):
Two CC 2.1.x sessions on the same Mac, same Anthropic account (cmux
auto-resume).
Session A actively in use; Session B idle with stale cached refresh token.
~10–28 min after A's auto-refresh, B's auto-refresh attempts to use its
now-
invalid refresh token. The 401 error path DELETES the canonical Keychain
entry,
knocking BOTH sessions logged-out and forcing /login.
Cycles observed: 28, 28, 34, 11 min between DELETE events. One clean REFRESH
(+1504 B, retained entry) seen between events 2 and 4. CPU snapshots at each
DELETE moment confirmed only the two CC PIDs alive; no Claude.app, no
chrome-native-host, no MCP build subprocesses, no claude-mem, no vibe-kanban.
NOT THE CAUSE (ruled out by methodical removal):
claude-mem worker daemon (chmod -x'd, settings disabled)
vibe-kanban MCP zombies (54 zombies purged, MCP removed)
claude -p build subprocesses (now inject parent OAuth token via
security find-generic-password -s "Claude Code-credentials" -w to skip
child-side refresh)
Claude Desktop crashpad helper (killed, behaviour unchanged)
Lone-session theory (initially considered; refuted — process snapshots
prove a sibling was always alive)
ARTIFACT CONSISTENT WITH STDIN-BUFFER-OVERFLOW HYPOTHESIS:
Multiple stale Claude Code-credentials- Keychain entries from
21–29 Apr, account marked "unknown". If the rumoured "large OAuth metadata
overflow on security -i stdin" fix is real, these orphans are its
fingerprint.
WORKAROUND: one CC session per Mac per Anthropic account. Hard rule. Cmux's
auto-resume of multiple CC sessions is the trap that surfaces this.
EVIDENCE AVAILABLE (happy to share on request):
Two deletion-.log watcher captures with full process snapshots
18 KB written-up investigation handoff with full timeline
keychain-watch.sh polling script (filesystem-event detection on
~/Library/Keychains/login.keychain-db)
Suggestion: an integration test that spins up two CC processes against a
mock OAuth server with refresh-token rotation enabled, runs them past
multiple refresh cycles, and asserts the canonical Keychain entry is never
DELETED on a 401 from a stale child token.

Environment Info

  • Platform: darwin
  • Terminal: ghostty
  • Version: 2.1.133
  • Feedback ID: 5a768c76-9f79-4344-ba6a-992cf29374c3

Errors

[{"error":"Error: NON-FATAL: Lock acquisition failed for /Users/jagan/.local/share/claude/versions/2.1.133 (expected in multi-process scenarios)\n    at _76 (/$bunfs/root/src/entrypoints/cli.js:2651:2257)\n    at yRH (/$bunfs/root/src/entrypoints/cli.js:2651:1337)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-05-08T16:04:33.299Z"},{"error":"Error: Failed to delete keychain entry: security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.\n    at Zuq (/$bunfs/root/src/entrypoints/cli.js:256:288713)\n    at async M39 (/$bunfs/root/src/entrypoints/cli.js:409:898)\n    at async Ba6 (/$bunfs/root/src/entrypoints/cli.js:409:796)\n    at async i$_ (/$bunfs/root/src/entrypoints/cli.js:2627:2259)\n    at async CRH (/$bunfs/root/src/entrypoints/cli.js:2653:5965)\n    at async <anonymous> (/$bunfs/root/src/entrypoints/cli.js:2678:3455)\n    at processTicksAndRejections (native:7:39)","timestamp":"2026-05-08T16:06:10.845Z"}]

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗