OAuth session silently invalidated: client_data returns empty, repeated /login prompts

Resolved 💬 3 comments Opened Mar 24, 2026 by ThomasDarby Closed May 3, 2026

Bug Description

Claude Code CLI repeatedly prompts for /login after every interaction, even though the OAuth token in the keychain is unexpired. This has been happening for several days and is severely disruptive to workflows.

Root Cause Investigation

I traced the issue to the client_data API endpoint returning empty data:

GET https://api.anthropic.com/api/oauth/claude_cli/client_data
→ 200 {"client_data": {}}

The OAuth token is technically valid (gets a 200 response), but the underlying session is invalidated server-side. The organizations endpoint confirms this:

GET https://api.anthropic.com/api/organizations
→ 403 {"error": {"type": "permission_error", "message": "Invalid authorization", "details": {"error_code": "account_session_invalid"}}}

This causes the CLI to:

  1. Cache hasAvailableSubscription: false in ~/.claude.json
  2. Cache clientDataCache.data: {} (empty)
  3. Prompt for /login to re-authenticate
  4. Fresh session works, then invalidates again within hours

Suspected Trigger

I frequently run multiple concurrent Claude Code sessions (2-3 processes) with parallel background agents. The token refresh code uses a file-lock mutex (proper-lockfile on the ~/.claude directory), but with multiple independent CLI processes, race conditions in the refresh flow may cause one process to invalidate another's session.

The decompiled refresh flow (QJq function) acquires a lock, checks if the token is still expired, then calls Kp_ to refresh. If two processes race past the expiry check before either acquires the lock, or if the Anthropic backend has a session concurrency limit, one refresh could invalidate the other's session.

Environment

  • Claude Code version: 2.1.81
  • Install method: native (macOS, arm64)
  • Subscription: Max (stripe_subscription)
  • OS: macOS Darwin 24.6.0
  • Auth method: OAuth (claude.ai)
  • Concurrent sessions: Typically 2-3 CLI processes with parallel background agents

Steps to Reproduce

  1. Run multiple concurrent Claude Code sessions (e.g., main session + background agents)
  2. Use sessions long enough for a token refresh cycle to occur
  3. After some time, one or more sessions will start showing "Not logged in" prompts
  4. Running /login fixes it temporarily, but the issue recurs

Expected Behavior

  • OAuth token refresh should be safe across concurrent CLI processes
  • client_data should never return empty {} for a valid, unexpired token
  • If a session is invalidated server-side, the refresh token should automatically recover without user intervention

Actual Behavior

  • Sessions are silently invalidated server-side
  • client_data returns 200 {"client_data": {}} instead of an error, making it a silent failure
  • The CLI caches the empty response and prompts for /login
  • This happens repeatedly, requiring manual /login after nearly every interaction

View original on GitHub ↗

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