Skip to content

fix: handle errSecInteractionNotAllowed in KeychainCacheStore to prevent cache self-destruction on wake#594

Open
josepe98 wants to merge 1 commit intosteipete:mainfrom
josepe98:fix/keychain-cache-interaction-not-allowed
Open

fix: handle errSecInteractionNotAllowed in KeychainCacheStore to prevent cache self-destruction on wake#594
josepe98 wants to merge 1 commit intosteipete:mainfrom
josepe98:fix/keychain-cache-interaction-not-allowed

Conversation

@josepe98
Copy link

Problem

When the Mac wakes from sleep, the keychain is briefly locked. During this window, KeychainCacheStore.load calls SecItemCopyMatching and gets back errSecInteractionNotAllowed (-25308). This falls into the default case, returns .invalid, and the caller deletes the cache entry:

// In Repository.loadRecord
case .invalid:
    KeychainCacheStore.clear(key: ClaudeOAuthCredentialsStore.cacheKey)  // cache wiped

The cache entry was perfectly valid — it was just temporarily inaccessible. Deleting it forces a fresh read of "Claude Code-credentials" on the next access, which triggers a keychain prompt. This is why users see repeated password prompts after wake from sleep even after clicking "Always Allow".

Fix

Two small changes to KeychainCacheStore.load:

  1. Apply KeychainNoUIQuery to the load query — consistent with how other no-UI reads are performed elsewhere in the codebase, and ensures the call fails fast with errSecInteractionNotAllowed rather than blocking.

  2. Add an explicit case errSecInteractionNotAllowed that returns .missing instead of .invalid. The entry is valid but temporarily inaccessible — the caller should fall through gracefully and retry on next access, not destroy the cache.

Context

errSecInteractionNotAllowed is already handled explicitly in ClaudeOAuthCredentials.swift and KeychainAccessPreflight.swift, but was missed in KeychainCacheStore itself. The KeychainNoUIQuery helper exists precisely for this purpose but wasn't applied to cache reads.

Note: I'm a user who hit this bug (repeated prompts after wake) and traced it to this specific code path.

…ent cache self-destruction on wake

When the keychain is temporarily locked (e.g. immediately after wake from
sleep), SecItemCopyMatching returns errSecInteractionNotAllowed (-25308).
Previously this fell into the default case, returned .invalid, and the
caller deleted the cache entry — causing every wake from sleep to require
a fresh read of "Claude Code-credentials", which triggers a keychain
prompt.

Two changes:
1. Apply KeychainNoUIQuery to the cache load query so the call never
   blocks waiting for UI interaction (consistent with how other no-UI
   reads are done elsewhere in the codebase).
2. Add an explicit case for errSecInteractionNotAllowed that returns
   .missing instead of .invalid — the entry is valid, just temporarily
   inaccessible, so it should not be deleted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant