Skip to content

[Bug]: Claude account switch skips running panes: only previous-account panes are candidates, and after an update none of those restarted #33551

Open

Description

@calvinberndt

Operating system

macOS

Orca version

1.4.240 (auto-updated from 1.4.237 a few minutes before the switches below)

Details

Summary

With When you switch accounts while Claude is running set to Always restart (claudeAccountSwitchRunningSessions: "restart"), two account switches in a row restarted 1 Claude terminal pane. 16 other panes stayed on an account that had reached its weekly limit, so every prompt in them returned "You've hit your weekly limit". The status bar showed the newly selected account with free usage, so the status bar and the running sessions disagreed, and no message said that panes were skipped.

There are two separate problems:

  1. By design, a switch only considers panes that it can tie to the account selected immediately before the switch. A pane that runs on an earlier account is never offered, even with Always restart.
  2. Right after the app updated, a switch away from the panes' own account also restarted none of them, although 11 of the 16 had an idle Claude status that pointed at that account.

What happened

One local host, terminal panes only. Orca started every Claude process (no hand-started claude, no tmux).

  1. 16 Claude panes ran on Account A. Each claude process has CLAUDE_CONFIG_DIR=<Orca user data>/claude-profiles/<A>/home. Orca 1.4.237 had started or resumed them one to two days earlier, several of them through its own restart-on-switch. A then reached its weekly limit.
  2. Orca auto-updated from 1.4.237 to 1.4.240 and relaunched. The 16 panes kept running in the previous version's terminal host. The process tree shows each claude under that host. New panes start in the new host.
  3. About 5 minutes later, I signed in again to Account B and selected it. No pane restarted. daemon.log shows no kill and no spawn in this window.
  4. A new Claude pane started on B, in the new terminal host.
  5. I selected Account C. Orca restarted only the B pane from step 4 ("Restarting 1 Claude session"). The 16 panes from step 1 stayed on A. After this step, a prompt in an A pane still returned A's weekly-limit error.

Checks after step 5:

  • ps eww for each of the 16 claude processes: CLAUDE_CONFIG_DIR is still A's folder, while claude-profiles/selected-host names C.
  • In orca worktree ps --json, 11 of the 16 panes had an idle (done) agent row. Their persisted hook status (agent-hooks/last-status.json) has a transcriptPath under A's folder. The other 5 panes had no agent row.

Cause, as far as I can trace it (v1.4.240 source)

  1. Only panes on the outgoing account are candidates. handleRunningClaudeSessionsAfterSwitch passes the account that was selected just before the switch as fromAccountId (claude-account-switch-sessions.ts L101, L121-L128). findMovableClaudeSessions drops every pane whose account is not exactly fromAccountId (claude-session-account-move.ts L195-L198). After A → B → C, the A panes can move only on a switch away from A. This fully explains step 5.

  2. The pane's account is inferred from its hook status, not recorded at launch. resolveClaudeSessionAccountId reads the account from providerSession.transcriptPath (L81-L102), and localClaudePanesInLane skips any pane that has no agentStatusByPaneKey entry (L145-L148). A pane without a status cannot be moved by any switch, even when it runs on the outgoing account. The 5 panes with no agent row in step 3 are likely this case.

  3. Not explained: in step 3, the 11 panes that had an idle status pointing at A were also skipped. What all 16 have in common is that they ran in the previous version's terminal host, while the one pane that did restart ran in the new host. The scan logs nothing, so I could not tell which check dropped them. Candidates are the renderer's ptyIdsByTabId binding after the relaunch (L134-L144), inspectRuntimeTerminalProcess against the old host, and isClaudeInForeground (L222-L230).

  4. The skip is silent. When the scan finds nothing, handleRunningClaudeSessionsAfterSwitch returns 'show-confirmation' (L134-L136). The status-bar menu ignores that result (ClaudeSwitcherMenu.tsx L193-L200), so a status-bar switch shows no message. The Settings path shows "Running sessions keep their account", which does not say which panes were skipped or why.

Codex already handles this case: listStaleCodexPanes compares each pane's recorded launch account with the active account, so every Codex pane that is not on the active account is flagged, whatever was selected before (codex-stale-pane-accounts.ts L15-L35). Claude panes have no such record.

Expected

After a switch, every running Claude terminal pane that is not on the newly selected account is restarted with claude --resume <session id> (Always restart) or listed in the Ask dialog. This includes panes started under an earlier account or System default, panes with no hook status, and panes still in the previous version's terminal host after an update. A pane that cannot be moved is listed with the reason.

Suggested fix

  1. Record each Claude pane's launch account when Orca starts Claude in it, as codex-pane-account-registry does for Codex. Orca already chooses the account at spawn (CLAUDE_CONFIG_DIR / ORCA_CLAUDE_INJECTED_CONFIG_DIR, and the claude shell function reads selected-host at each launch).
  2. In the switch handler, select every Claude pane whose recorded account is not the new account (a Claude version of listStaleCodexPanes), instead of accountId === fromAccountId. Leave out panes that are kept on their account (feat(accounts): keep a Claude or Codex agent on its account #28684).
  3. Do not require a live hook status. Use the recorded launch account, a foreground-process check that also works for panes in an older terminal host, and a session id from the recorded provider session or from Claude's <CLAUDE_CONFIG_DIR>/sessions/<pid>.json.
  4. Name the skipped panes in the toast or dialog, and log one line per skipped pane with the check that dropped it.

Steps to reproduce (problem 1)

  1. Add three Claude accounts A, B and C. Set the switch setting to Ask.
  2. Select A. Start a Claude pane P1 and send one prompt.
  3. Select B. In the dialog, choose Keep as is. P1 stays on A.
  4. Start a Claude pane P2 on B and send one prompt. Set the switch setting to Always restart.
  5. Select C. Only P2 restarts. P1 stays on A, and no message mentions it.

I have not reproduced problem 2 in isolation. It happened on the first switch after an auto-update, with all affected panes still in the previous version's terminal host.

Workaround

In each stuck pane, run /exit, then claude --resume <session id> in the same pane. Orca's claude shell function starts it on the selected account.

Do not use /login inside the pane. It writes the new login into the pane's account folder, so the Orca account entry that owns that folder now holds a different login. Afterwards, Orca listed two account entries with the same email.

Related

Activity

  1. AmethystLiang commented on Oct 25, 2026

    @AmethystLiang
    Contributor

    looking into it

  2. JahyunBaek commented on Oct 27, 2026

    @JahyunBaek
    Contributor

    Windows 11 reproduction of problem 2 on 1.4.242, with Always restart set. Same shape as yours: only the pane in the new terminal host restarted.

    Timeline from the process tree and file times (local time, 10-27):

    • 10:11 — auto-update to 1.4.242 and relaunch.
    • 10:32:51 — first account switch after the update (claude-profiles/selected-host rewritten).
    • 10:32:56 — one claude.exe --resume starts under the 1.4.242 terminal host. That pane restarted.
    • No pane in an older terminal host restarted, including the one I was looking at, which was on the outgoing account. Those hosts survived several updates: 6 Claude panes run under daemon-host-profiles\<id>\1.4.239\…\Orca.exe, and 1 under …\1.4.235\…\Orca.exe, whose Claude has been running since 10-23.
    • I restarted three of them by hand with /exit and claude --resume <id> in the same pane. The new processes still start under the 1.4.239 host.

    So on Windows too, a pane's terminal host seems to be what decides whether the switch reaches it.

  3. Tauri-EPO commented on Oct 27, 2026

    @Tauri-EPO
    Contributor

    One more cause for the same symptom, from a Windows host. It may help separate the cases: here the switch did restart panes from the previous terminal host, and the pane that stayed behind was skipped for a different reason.

    Setup

    • Windows 11 Pro, Orca 1.4.241 (updated from 1.4.240 about 3 hours before the switch). The affected pane's PTY carries ORCA_APP_VERSION=1.4.239.
    • Claude Code 2.1.310 in all panes.
    • claudeAccountSwitchRunningSessions: "restart" (Always restart).
    • The affected pane runs an orchestration coordinator. Between turns it always keeps one background shell running (a run_in_background watch loop that waits for orchestration mail).

    What happened (one switch, 2026-10-26 17:08:18Z, account A → B)

    • claude-profiles/selected-host was rewritten to B's home at 17:08:18Z.
    • daemon.log shows four panes closed (cause: operator_close) at 17:08:19Z and respawned within one second, each with a 56-character startup command, which fits claude --resume <uuid>. Three of the four were in the previous terminal host (daemon pid 65064). The other one was in the new host (pid 12012). So on this machine, panes in the previous version's host did restart.
    • The coordinator pane was not restarted. Its claude process still has CLAUDE_CONFIG_DIR=<userData>\claude-profiles\<A>\home 35 minutes later.

    Why the coordinator pane stays on A

    agent-hooks/last-status.json for that pane, 17:43Z:

    "state": "working",
    "mainAgent": { "state": "done", "stateStartedAt": 17:36:01Z },
    "claudeRunningNonAgentTask": true,
    "stateStartedAt": 17:02:39Z,
    "providerSession": { "transcriptPath": "<userData>\\claude-profiles\\<A>\\home\\projects\\...\\<session>.jsonl" }
    

    The transcript shows the main agent ending turns at 17:08:03, 17:13:50, 17:19:48, 17:34:00 and 17:36:01Z. In each gap the background shell was still running, so the pane's combined state stayed working (monitoring) from 17:02:39Z on. It never reached done.

    In v1.4.241 that blocks the restart:

    • foldAgentLeadStatus (src/shared/agent-lead-status-fold.ts L31-L39) maps "lead done + live child shell" to working / monitoring.
    • isClaudePaneMidTurn (src/renderer/src/lib/claude-session-account-move.ts L67-L70) treats any combined state other than done as mid-turn.
    • Both executors wait on it: selectReadyAccountRestartPtyIds / isAccountRestartReady (pane-account-restart-readiness.ts L6-L29) for mounted panes, and restartUnclaimedPane (codex-detached-pane-restart.ts L79-L85) for detached ones.

    The transcript path is under A's folder, so resolveClaudeSessionAccountId returns A, which equals fromAccountId. The pane therefore meets the candidate rules you listed. I can't read the renderer's pendingPaneAccountRestarts from disk, so I can't prove that the pane was queued rather than dropped by a later check. If it was queued, the restart waits for a done state that an agent with a permanent background watch never reaches.

    As far as I can see, nothing shows that a Claude restart is waiting. For Codex, CodexRestartChip shows "Codex is using the previous account" on the pane, and the status bar counts stale sessions and has a Restart button. The Claude path queues the restart with no notice (queuePaneAccountRestarts returns before touching any notice for 'claude', terminal-restart-state.ts L56-L58). This matches the reports in #29870 that long-running coordinators are the sessions that stay behind.

    What would help (in addition to the fixes proposed above)

    1. A pane-level and status-bar notice for Claude panes still on another account, reusing the Codex restart notice, with "Restart now" and "Keep". It should also show when a restart is queued behind background work ("Restarts on B when its background tasks finish").
    2. When the lead's own turn is over and only background shells hold the pane, either ask before restarting (restarting ends those shells) or offer "Restart now". Waiting with no notice is the one option that leaves the pane on the wrong account indefinitely.
    3. A way for the agent in the pane to see that it is on a stale account, for example in orca status --json or the orchestration check receipt. A coordinator could then end its watch loop at a safe point and let the queued restart run. This is related to [Feature]: Switch an existing coordinator between providers without losing conversation or orchestration state #29871.

    Reproduced: observed once on 2026-10-26 in normal use (evidence above); not yet re-run as a controlled repro. The steps below are how I would reproduce it.

    Steps to reproduce

    1. Add two Claude accounts A and B. Set "When you switch accounts while Claude is running" to Always restart. Select A.
    2. Start a Claude pane P1. Ask it to start a background shell that runs for 10 minutes (for example sleep 600 with run_in_background) and then end its turn.
    3. Start a second Claude pane P2, send one prompt, and let it go idle.
    4. Select B.
    5. Expected: P1 and P2 both restart, or P1 shows that it is waiting. Actual: P2 restarts right away. P1 keeps running on A with no notice and restarts only after the background shell ends. If the shell is replaced by a loop that never ends, P1 never restarts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

os:macosIssues affecting macOS

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions