Auto-update silently fails when npm global folder isn't writable, then forces re-login on next run

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Aug 13, 2026

Title

Auto-update silently fails when npm global folder isn't writable, then forces re-login on next run

Description

On a system where the npm global install directory isn't writable by the running user, claude update (and presumably the background auto-updater) fails to install the new version — but the failure isn't clearly surfaced, and afterwards I'm forced to fully re-authenticate (/login) even though my previous session and refresh token were still valid.

This happened repeatedly across multiple update cycles before I diagnosed the root cause.

Environment

  • Claude Code version at time of issue: 2.1.220 (npm global install)
  • OS: Linux (Ubuntu, systemd)
  • Auth method: Claude subscription (OAuth login, not API key)
  • npm global prefix: /usr/local, owned by nobody:nogroup (not writable by the invoking user)

Steps to reproduce

  1. Install Claude Code via npm global (npm install -g @anthropic-ai/claude-code) on a system where /usr/local/lib/node_modules is not writable by your user.
  2. Log in normally via /login with a Claude subscription.
  3. Run claude update (or wait for background auto-update).
  4. Observe:

``
Warning: Can't auto-update: npm global folder isn't writable
Fix: Run claude install to switch to the native installer (no sudo)
New version available: 2.1.231 (current: 2.1.220)
Installing update...
Using global installation update method...
Error: Failed to install update
``

  1. Start claude again — prompted to log in again, despite the previous session working fine and the refresh token still being valid.

Diagnostic details

Inspecting ~/.claude/.credentials.json around the time of the forced logout showed:

  • claudeAiOauth.expiresAt = 0
  • claudeAiOauth.refreshTokenExpiresAt = a valid future timestamp (~15 days out)

Note: after switching to the native installer (claude install), the same credentials file (same expiresAt: 0, unchanged mtime) continued to work without forcing a re-login — so expiresAt: 0 on its own does not appear to be the trigger. The forced re-login seems tied specifically to the failed/partial auto-update attempt on the unwritable npm global install, not to the credentials file contents.

Also checked and ruled out

  • System clock: NTP active, offset ~1.4s — not the cause.
  • ~/.claude/.credentials.json permissions: correct (0600, owned by the running user).

Suggested fix

  1. When auto-update detects an unwritable npm global folder, fail gracefully without touching the stored session/credentials, and surface a clear one-time notice to run claude install — rather than leaving the CLI in a state that later forces a full re-login.
  2. Consider proactively detecting this on first run (unwritable global npm folder) and recommending the native installer before the user hits a failed update.

Workaround

Switching to the native installer resolved it:

claude install

View original on GitHub ↗