[BUG] Desktop app shows 'GitHub CLI authentication expired' banner while gh credentials are valid (Keychain storage)
Environment
- Claude Code version: 2.1.143 (desktop app, macOS)
- Platform: macOS 15.6.1 (Sequoia)
- gh version: 2.79.0 (2025-09-08)
- gh token storage: macOS Keychain (
keyring)
Bug description
The desktop app repeatedly shows this banner:
⚠️ GitHub CLI authentication expired. Run gh auth login to refresh pull request status.
But the GitHub CLI credentials are valid at the moment the banner appears. Verified in the same session, seconds apart:
$ gh auth status
github.com
✓ Logged in to github.com account earlyspark (keyring)
- Active account: true
- Git operations protocol: https
- Token: gho_************************************
- Token scopes: 'admin:public_key', 'gist', 'read:org', 'repo', 'workflow'
$ gh api user --jq .login
earlyspark
The banner reappeared after being dismissed, again with gh auth status and a live gh api call succeeding at the same time.
Expected behavior
No "authentication expired" banner when gh credentials are valid and working.
Suspected cause
The token is stored in the macOS Keychain. If the desktop app checks PR status by invoking gh from a background/non-interactive context, Keychain reads can fail there even though they succeed in an interactive shell — and the failure is then misreported as an expired token. This would make the banner's suggested fix (gh auth login) a no-op, since the token itself is fine.
Possibly related:
- #7771 —
/install-github-appclaimsghis not authenticated when it is - #56000 — GitHub repository access check fails despite valid
ghcredentials - #44089 / #44028 — macOS Keychain inaccessible outside a GUI shell session
Steps to reproduce
- macOS, Claude Code desktop app,
ghauthenticated with token in Keychain (gh auth login, default secure storage). - Use the app normally in a git repo with a GitHub remote.
- Banner appears claiming
ghauth expired;gh auth statusandgh api usersucceed at the same moment.
Impact
Cosmetic but recurring — the banner re-appears after dismissal and prompts users toward an unnecessary re-login (or worse, toward --insecure-storage to silence it).
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗