[Bug] Daemon proactive refresh hangs ~9h on Windows, falls back to non-existent keychain

Status Open
Reported on v2.1.235
Maintainer reply None cached
Activity 1 comment · opened Aug 19, 2026

Bug Description

Daily forced re-login on Windows: daemon proactive refresh hangs ~9h, then falls back to a keychain that doesn't exist

Summary

Every morning I have to run a full OAuth login again, even though my refresh
token is valid for another ~29 days. The daemon's proactive refresh appears to
hang for roughly nine hours and then give up, and its recovery path looks for a
"keychain" that has no Windows implementation enabled on my account.

The re-login itself is slow because the confirmation email takes ~20 minutes to
arrive, so this costs real time each day.

Environment

  • Windows 11 Pro 10.0.26200
  • Credentials stored in plaintext at ~/.claude/.credentials.json
  • cmdkey /list shows no Claude/Anthropic entries in Windows Credential Manager
  • Feature flag tengu_windows_credman = false for this account
  • Subscription type: team

What I expect

The access token has an ~8h lifetime, so overnight expiry is normal and
expected. Claude Code should use the still-valid refresh token to mint a new
access token silently. I should not see a login prompt.

What actually happens

Token state captured immediately after a successful login:

  • accessToken expires: ~8 hours later (same evening)
  • refreshToken expires: ~29 days later

So the credential needed for a silent refresh is present and valid at the moment
the forced re-login is demanded.

Daemon log evidence

From ~/.claude/daemon.log. The pattern repeats on 12→13 Aug, 13→14 Aug, and
17 Aug:

[2026-08-13T17:30:10.855Z] [supervisor] auth: proactive refresh starting
[2026-08-14T02:06:15.224Z] [supervisor] auth: proactive refresh failed, signalling re-auth required
[2026-08-14T02:06:15.282Z] [supervisor] auth: headless daemon cannot complete OAuth — run `claude auth login` to refresh
[2026-08-14T02:06:15.287Z] [supervisor] auth: no token found, will re-check keychain every 30s
[2026-08-14T04:11:36.689Z] [supervisor] auth: scheduling proactive refresh in 21040s
[2026-08-14T04:11:36.689Z] [supervisor] auth: token found via keychain re-check

Earlier occurrence, same shape:

[2026-08-12T17:06:37.030Z] [supervisor] auth: proactive refresh starting
[2026-08-13T02:03:31.960Z] [supervisor] auth: proactive refresh failed, signalling re-auth required

Two things that look wrong

1. Refresh start → failure gap is ~9 hours.
17:30 to 02:06, and 17:06 to 02:03. A token refresh is a single HTTPS call that
should complete or fail in well under a second. A nine-hour gap looks like the
request hangs with no timeout until the access token expires underneath it,
rather than the refresh token being rejected. A rejected refresh token should
fail immediately.

2. The fallback path references a keychain on Windows.
auth: no token found, will re-check keychain every 30s — "keychain" is macOS
credential storage. On this machine credentials are in a plaintext JSON file and
tengu_windows_credman is false, so there is no Credential Manager entry either.
I don't know whether the credman backend and the daemon refresh path are the same
code, so this may be a red herring, but the platform mismatch in the log message
is at least confusing and possibly the reason recovery never succeeds.

Other state

~/.claude/daemon-auth-status.json has been stuck for several days:

{"status":"auth_required","since":1786926514042}

That timestamp is 15 Aug. Interactive sessions still work normally during this
period — it's specifically the unattended refresh that never recovers.

Ruled out

  • Not a credential save failure. .credentials.json is rewritten correctly

on every login (verified by mtime immediately after logging in).

  • Not ~/.claude.json. Its oauthAccount key holds profile metadata only

(account UUID, email, org, seat tier) — no tokens. It is not a competing
credential store.

  • Possibly unrelated: CLAUDE_CODE_OAUTH_TOKEN is set as a User-level

Windows environment variable on this machine, and /login warns about it. I
have no evidence it is causing this, and interactive logins work fine, but
mentioning it in case the daemon reads it at startup and skips the on-disk
refresh path as a result.

Impact

One full OAuth re-login every morning, each gated on a ~20 minute confirmation
email, despite holding a refresh token valid for another month.

Environment Info

  • Platform: win32
  • Terminal: null
  • Version: 2.1.235
  • Feedback ID: 089b74eb-863d-4d62-994f-0d6839c9469d

Errors

[]

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗