anthropics / anthropics/claude-code
/login reports "Login successful" but token is never saved: ENOTDIR rmdir on stale .storage-write.lock file (2.1.277)
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
### Preflight Checklist
- [x] I have searched [existing issues](https://github.com/anthropics/claude-code/issues?q=is%3Aissue%20state%3Aopen%20label%3Abug) and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
### What's Wrong?
After updating to 2.1.277 (auto-update, 2026-09-18), every request failed with auth errors that cycled through `API Error: 401 OAuth access token has been revoked`, then `Anthropic profile login expired`, then `Not logged in · Please run /login`.
`/login` (in-session) and `claude auth login` (CLI) both complete the browser OAuth flow and print `Login successful`, but nothing is persisted. Immediately afterward:
- `claude auth status` → `"loggedIn": false, "authMethod": "none"`
- `security find-generic-password -s "Claude Code-credentials"` → item not found
- `~/.claude/.credentials.json` → does not exist
The Keychain itself is writable (verified with `security add-generic-password` / `find` / `delete` from the same shell). `claude doctor` reports "No installation issues found" while also reporting "Not signed in to claude.ai".
Root cause, from the debug log: the credential save fails because `~/.claude/.storage-write.lock` existed as a regular file rather than a directory, so the lock cleanup `rmdir` threw `ENOTDIR`. The OAuth exchange had already succeeded, so the UI reported success while the token was silently dropped. Deleting the stale file fixed it on the next `claude auth login`.
Full logout, Keychain item deletion, removing `~/.claude/.credentials.json` and `~/.config/anthropic`, and restarting did not help until the lock file was removed. Side effects while in this state: all MCP servers showed "needs authentication", remote managed settings failed to fetch, and Remote Control reported "Sign-in is missing the user:profile scope" even though the login URL requested that scope.
### What Should Happen?
Either of:
1. The credential store should tolerate a stale `.storage-write.lock` that is a regular file (unlink it, or use a lock strategy that can't be left behind as a file), so the token save succeeds.
2. At minimum, if the token save fails, `/login` and `claude auth login` should surface the error instead of printing `Login successful`. The `Failed to save OAuth tokens` error only appears in the `--debug` log, and `claude doctor` says "No installation issues found", so there is no user-visible signal pointing at the actual cause.
### Error Messages/Logs
```shell
From ~/.claude/debug/.txt during a /login in a `claude --debug` session:
2026-09-18T18:27:09.126Z [ERROR] Failed to save OAuth tokens: ENOTDIR: not a directory, rmdir '/Users//.claude/.storage-write.lock'
2026-09-18T18:27:09.747Z [DEBUG] [Bootstrap] Skipped: no usable OAuth, WIF, or API key
2026-09-18T18:27:28.457Z [ERROR] API error (attempt 1/11): Could not resolve authentication method. Expected one of apiKey, authToken, credentials, config, or profile to be set. Or for one of the "X-Api-Key" or "Authorization" headers to be explicitly omitted
2026-09-18T18:26:37.895Z [DEBUG] [Claude in Chrome] Disabled: OAuth token has no scope accepted by /api/oauth/validate (needs user:profile, user:office, or user:ccr_inference; ...)
2026-09-18T18:26:53.981Z [ERROR] [Anthropic telemetry] Failed to check metrics opt-out status: Auth error: no credential usable for the metrics opt-out check
CLI:
$ claude auth login
Opening browser to sign in…
Paste code here if prompted > Login successful.
$ claude auth status
{ "loggedIn": false, "authMethod": "none", "apiProvider": "firstParty", ... }
claude doctor (relevant lines):
Running: native (2.1.277)
Last update attempt: success → 2.1.277 (2026-09-18)
Managed settings (remote): not fetched — no usable credentials for the settings fetch
Organization policy: not fetched: no API key or claude.ai sign-in for the policy lookup
Remote Control: Not signed in to claude.ai / Sign-in is missing the user:profile scope
No installation issues found.
In-session messages seen over the course of the failure, in order:
- Please run /login · API Error: 401 OAuth access token has been revoked.
- Anthropic profile login expired · Run /login to use your claude.ai account instead, or re-authenticate the profile
- Not logged in · Please run /login
- ⚠ Remote managed settings failed to load (the profile credential could not authenticate the fetch)
- ⚠ 3 MCP servers need authentication · run /mcp
```
### Steps to Reproduce
Reproduce the stale-lock state directly:
1. `claude auth logout`
2. `touch ~/.claude/.storage-write.lock` (a regular file, simulating whatever left it behind; in my case it appeared around the auto-update to 2.1.277)
3. `claude auth login` and complete the browser flow → prints `Login successful.`
4. `claude auth status` → `"loggedIn": false`
5. `claude --debug`, run `/login`, then grep the newest `~/.claude/debug/*.txt` for `Failed to save OAuth tokens` → `ENOTDIR: not a directory, rmdir '.../.claude/.storage-write.lock'`
Fix/workaround:
6. `rm -f ~/.claude/.storage-write.lock`
7. `claude auth login` → `claude auth status` now shows `"loggedIn": true, "authMethod": "claude.ai"`
I did not determine what originally created the lock as a file. Timeline: everything worked before the 2026-09-18 auto-update to 2.1.277; first symptom was the 401 revoked-token error in an existing session immediately after.
### Claude Model
None
### Is this a regression?
Yes, this worked in a previous version
### Last Working Version
_No response_
### Claude Code Version
2.1.277 (Claude Code), native install, darwin-arm64, commit 97305f0832e6
### Platform
Anthropic API
### Operating System
macOS
### Terminal/Shell
Terminal.app (macOS)
### Additional Information
- Auth: claude.ai account (Max subscription), no ANTHROPIC_API_KEY, no CLAUDE_CONFIG_DIR, no apiKeyHelper, no ANTHROPIC_PROFILE.
- Keychain is the default login keychain and writes from the same shell succeed.
- Plugins enabled: vercel, posthog (claude-plugins-official), last30days.
- Existing issues searched: this is the macOS counterpart of #62600 ("Windows: stale lock directories block credential persistence after abnormal exit", closed as stale and locked, which asks for a new issue referencing it) and #71717. Same mechanism (mkdir-as-mutex lock left behind, /login reports success, credentials never written); the difference here is the stale `.storage-write.lock` was a regular file rather than a directory, so the failure surfaces as `ENOTDIR` on `rmdir`. Also likely related to #95386 and #87192.
- Suggestion: have `claude doctor` / `/doctor` check for a stale `*.lock` in the config dir, since it currently reports a clean install in this state.
- Candidate cause: a prior version was running in an active session when the auto-update to 2.1.277 landed, so a change in lock format between builds (file-based vs mkdir-based) is a likely way the lock ended up as a regular file. Nothing else writes to `~/.claude/` on this machine.
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce with `touch ~/.claude/.storage-write.lock`, then run `claude auth login` and inspect the newest `~/.claude/debug/*.txt` for the token-save failure. Trace the credential save and lock cleanup used by `claude auth login` and in-session `/login`; done means a regular stale lock no longer prevents persistence, or the login surfaces the save error instead of reporting success.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cli, macos
- Domain
- authentication, cli, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100