[BUG] /usage hangs indefinitely after OAuth token expires (idle session)
Description
When Claude Code has been running for an extended period (e.g. left open overnight while waiting on token limits), the OAuth session token expires. After returning to the terminal, typing /usage results in an indefinite "Loading..." spinner — the command never resolves and provides no error or recovery path.
The workaround is to send any trivial prompt (e.g. "say hello"), which triggers a real completion request, implicitly refreshes the expired token, and restores the session. Subsequent /usage invocations then work correctly.
This implies that /usage does not go through the same token-refresh path used by the completions API. Since /usage contacts the Anthropic servers to fetch usage data, it should be able to trigger the same re-authentication flow — or at minimum, fail with a clear actionable error rather than hanging.
Steps to Reproduce
- Start a Claude Code session and authenticate normally.
- Leave the process running without sending any prompts for several hours (long enough for the OAuth token to expire — typically 4–8 hours).
- Return to the terminal and type
/usage.
Expected Behavior
One of:
/usageproactively checks token expiry, refreshes the token, then fetches and displays usage data./usagedetects the expired token, surfaces a clear message such as: _"Session expired. Send any prompt or run/loginto re-authenticate."_ (this would require manual re-auth though - which is annoying if done manually)
The current silent outcome is not acceptable.
Actual Behavior
The /usage command displays "Loading..." and never resolves. No timeout, no error message, no recovery path is shown. The only way to recover is to send a regular prompt, which implicitly refreshes the token as a side effect.
Environment
- Platform: macOS
- Shell: zsh
- Trigger: OAuth token expiry after idle session (no prompts sent)
Related Issues
- #21637 —
/usagehangs after several hours of terminal idle (closed 2026-03-02). Root cause attributed to stale connection / session handle. This report identifies token expiry as a contributing (or independent) cause, confirmed by the "send any prompt to recover" workaround. - #30221 —
/usageshows indefinite loading after idle terminal, lock acquisition failures (closed 2026-03-31). Same symptom; attributed to event logging timeouts.
Both prior issues are closed. This report adds a concrete reproduction path and a specific diagnosis: the /usage handler does not participate in the session's token-refresh lifecycle.
Proposed Fix (Sketch)
The usage fetch should go through the same authenticated HTTP client / token-refresh middleware used by the completions path. At minimum:
- Before making the usage API request, check whether the current token is expired and refresh it using the stored refresh token — mirroring what a regular prompt triggers implicitly.
- If refresh fails (no refresh token, network error), surface a clear error message rather than hanging indefinitely.
- Add a timeout + error boundary to the usage fetch so it cannot hang regardless of auth state. A 10–15 second timeout with a user-visible error is far better than an indefinite spinner.
The same pattern should apply to any other slash command that makes network requests (e.g. /status, /login polling).
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗