anthropics / anthropics/claude-code
remote-control session permanently 401s after token refresh fails; /login cannot reach the process
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
### What happened
A long-running session spawned by `claude remote-control` caches its OAuth credentials at process start. Once the in-memory access token expires and the refresh attempt fails, that session returns a 401 forever and there is no way to re-authenticate it in place.
The session transcript records, on every subsequent message:
```
"subtype": "api_error", "status": 401,
"formatted": "401 OAuth access token has expired. Re-authenticate to continue."
"retryAttempt": 1, "maxRetries": 10
```
The client UI then shows a banner telling the user to sign in again on their computer.
### Why it is not recoverable
Two obvious recovery paths both fail:
1. **`claude /login` in a separate terminal** — this succeeds and updates the credential store (I verified the new access token and a refresh token ~29 days out). The already-running session process never re-reads it. 401s continued 2 and 3 minutes *after* a successful login.
2. **Typing `/login` into the session's own input box on claude.ai** — never reaches the process. The transcript shows no `/login` being received; while the "sign in again" banner is displayed, the UI appears to re-send the previously pending message instead of the new input. So the one slash command that could fix the session cannot be delivered to it.
The session process has no TTY (it is a child of `~/.claude/remote/srv//server --serve`, itself under launchd), so there is no terminal route to it either.
### Only workaround found
Kill the remote-control agent and let launchd restart it. This works — the new agent picks up the current credentials — but **every bridged `claude.ai/code/session_*` URL is destroyed**, because new sessions get new IDs. In my case 14 sessions were lost this way; their transcripts survived on disk and had to be reopened individually with `claude --resume `.
### Impact
This is the normal remote workflow: work against the Mac from another machine (SSH / browser), come back later, continue. Instead, every bridged session becomes permanently unusable and the session URLs are lost. Transcripts are not lost, but the shared/bridged sessions are.
### Steps to reproduce
1. Run `claude remote-control` (launchd agent) and open a session from claude.ai.
2. Leave it running long enough for the access token to expire and the refresh to fail (in my case the refresh token was itself near expiry).
3. Send a message → `401 OAuth access token has expired`.
4. Run `claude /login` in a terminal; confirm the credential store is updated.
5. Send a message in that session again → still 401.
6. Type `/login` in that session's input box → not delivered; still 401.
### Expected
- Re-read the credential store when a request fails with 401 `authentication_error`, instead of retrying the same dead token 10 times.
- At minimum, accept `/login` typed into a bridged session's input box, and preserve the session/bridge URL across a re-authentication.
### Environment
- macOS 15.6 (Darwin 25.6.0), Apple Silicon
- Claude Code 2.1.268 (CLI), remote `ccd-cli` 2.1.271, desktop-bundled claude-code 2.1.270
- Claude Max subscription, OAuth login (not API key)
- Credentials in macOS Keychain; `~/.claude/.credentials.json` was present but empty (`accessToken: ""`, `expiresAt: 0`) — possibly related, as the failing processes are the `remote/ccd-cli` ones.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the `claude remote-control` launchd agent at `~/.claude/remote/srv//server --serve` and the `/login` command path. Reproduce the expired-token 401 after `claude /login` updates the credential store, then verify that re-authentication restores the existing bridged session and preserves its URL without restarting the agent.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, python
- Domain
- authentication, backend, cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100