Skip to content

Agents panel reports SIGN-IN EXPIRED when only the 8-hour access token lapsed #12470

Description

@echelonzero

System details

Intel i7-1185G7 / Iris Xe, Omarchy 4.0.3-1, Claude Code 2.1.265. bin/omarchy-agent-usage-claude on this machine is byte-identical to quattro HEAD, so the line numbers below are current.

What's wrong?

Leave the machine alone for ~8 hours and the agents panel reports SIGN-IN EXPIRED over stale limits. The sign-in has not expired. Launching claude clears it immediately.

Repro

  1. Sign in to Claude Code, open the agents panel, confirm the limits are live.
  2. Don't run claude for 8+ hours (overnight is enough).
  3. Open the panel: SIGN-IN EXPIRED, "showing the last known limits", bars frozen where they last read.
  4. Run claude in a terminal, then reopen the panel — green again.

Why

collect_limits branches on one field, bin/omarchy-agent-usage-claude:813:

if expires_at_ms > 0 and expires_at_ms <= time.time() * 1000:
    result["limits"] = fallback
    result["usageStatusText"] = "Sign-in expired"

expires_at_ms comes from claudeAiOauth.expiresAt in ~/.claude/.credentials.json (oauth_login, line 584). That is the access token, and it lives about 8 hours. The same file carries claudeAiOauth.refreshTokenExpiresAt — the actual sign-in — which is good for about 30 days. On this machine the access token lapses ~8h after the last claude run while the refresh token still has three weeks on it, and the panel calls that an expired sign-in.

The comment above the branch shows the 8-hour lapse is known and the message is deliberate. The lapse isn't the complaint; the wording is. SIGN-IN EXPIRED in the panel header, plus "Start Claude Code, or run claude auth login, to refresh it", tells a user their session died and invites a re-auth that isn't needed — for a cache that expired on schedule. Users will re-login, which is a browser round trip to fix nothing.

Two ways out, either is fine

  1. Refresh instead of reporting. The refresh token is right there in the file. A collector that mints its own access token keeps the panel live without the CLI, and the "lapsed token" state stops existing.
  2. Say what was measured. Keep the passive behaviour, but distinguish the two. Check refreshTokenExpiresAt first: if that has passed, Sign-in expired is the truth and claude auth login is the fix. If it hasn't, the state is a stale access token — something like Limits paused — run claude to refresh — and the help text should not mention re-authenticating.

Option 2 is the smaller change and removes the misleading half. Worth noting that option 1 has a sharp edge: a rejected refresh makes the CLI drop the stored tokens, so a collector doing its own refresh needs to handle rotation and write-back carefully, and races with a running CLI over the same file.

Which commands actually refresh — measured against a throwaway CLAUDE_CONFIG_DIR copy, so the real credential file was never touched. Useful if anyone documents a workaround:

  • claude auth status does not refresh. Handed an expired token it reports loggedIn:true and leaves the file byte-identical.
  • claude doctor does. Handed an expired token and a deliberately bogus refresh token, it came back with the stored tokens cleared — the server rejected the refresh — while the same run with the network blackholed (HTTPS_PROXY at a dead port) left the file untouched. Only a real round trip to the token endpoint explains the difference.

Locally I've worked around it with a user timer running claude doctor every 6 hours, which keeps the access token inside its window and the panel green. That's a patch on my side, not a fix — the panel is still reporting the wrong thing when it fires late.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions