Correct what a switch actually does to a running session
Every one of these said a switch leaves running sessions alone - that they keep talking to the old provider until restarted. That is wrong, and reassuring in exactly the wrong direction: a switch breaks them. The static half of the config does behave as described. Base URL, model ids and the env block are read once at startup and a running session keeps what it started with. The credential is not. It comes from running apiKeyHelper, which Claude Code re-invokes on a timer - CLAUDE_CODE_API_KEY_HELPER_TTL_MS is present in the 2.1.251 binary - and claude-key-helper.sh answers for whatever state.json says at that moment. So the switch reaches into a live session through the one part that was never cached. Into anthropic, the helper returns nothing by design and the next refresh comes back with no credential; into another provider, it hands over the new key while the session is still pointed at the old base URL, which rejects it. Either way the session starts failing calls whenever the TTL happens to expire, mid-turn as easily as between turns. One case does survive, and is now stated rather than glossed: switching between two presets of the same provider that share a keyRef keeps the same key and the same endpoint, so the session carries on with the model ids it started with. The claim in "Restarting sessions" predates this work - it came in with the Windows build - but it is wrong for the same reason and is corrected too.
This commit is contained in:
@@ -300,9 +300,27 @@ If the profile doesn't load: `Set-ExecutionPolicy -Scope CurrentUser RemoteSigne
|
||||
|
||||
## Restarting sessions
|
||||
|
||||
Claude Code reads all of this **once at startup**. A switch does not affect a
|
||||
running session — that's how the process loads config, not something scripting
|
||||
can change.
|
||||
A switch **breaks** running sessions. This originally said it did not affect
|
||||
them; that was wrong, and the difference matters, because the two halves of the
|
||||
config behave differently.
|
||||
|
||||
The static half — base URL, model ids, the env block — genuinely is read once at
|
||||
startup, and a running session keeps what it started with.
|
||||
|
||||
The credential is not. It comes from running `apiKeyHelper`, which Claude Code
|
||||
re-invokes on a timer (`CLAUDE_CODE_API_KEY_HELPER_TTL_MS`, present in 2.1.251),
|
||||
and the helper answers for whatever `state.json` says *at that moment*. So a
|
||||
switch reaches into a live session through the one thing that was never cached:
|
||||
|
||||
| switching to | what the running session gets |
|
||||
|---|---|
|
||||
| `anthropic` | the helper returns nothing, by design — no credential at all |
|
||||
| another provider | the new provider's key, sent to the old base URL, which rejects it |
|
||||
| another preset of the *same* provider, same `keyRef` | same key, same endpoint — this one survives, on the model ids it started with |
|
||||
|
||||
Either of the first two starts failing calls whenever the TTL happens to expire:
|
||||
mid-turn as easily as between turns. So restart afterwards — and on Linux,
|
||||
`claude-mode sessions --restart` will do it for you:
|
||||
|
||||
- **CLI** — exit and relaunch `claude`
|
||||
- **VS Code** — `Ctrl+Shift+P` → *Developer: Reload Window*
|
||||
@@ -446,12 +464,11 @@ stays exactly as it was.
|
||||
|
||||
## Sessions still on the old provider
|
||||
|
||||
Claude Code reads all of this once, at startup. A switch therefore does nothing
|
||||
to a session already running: it keeps talking to the old provider on the old
|
||||
key until it is restarted, which is the confusing part — the bar says one thing
|
||||
and the session in front of you is doing another. A session mid-request is worse
|
||||
off, because anthropic mode *deletes* the helper, so an in-flight turn can fail
|
||||
on its next tool call rather than stopping cleanly.
|
||||
A switch does not leave running sessions on the old provider — it breaks them.
|
||||
See [Restarting sessions](#restarting-sessions) for the mechanism: their
|
||||
endpoint is fixed at startup but their credential is re-fetched on a timer, so
|
||||
it switches under them and the endpoint they are still pointed at refuses it.
|
||||
Which is why this is a decision rather than a notification.
|
||||
|
||||
```
|
||||
claude-mode sessions
|
||||
|
||||
Reference in New Issue
Block a user