stablyai/orca · warning · Error

A Claude account switch is already in progress.

Error message

A Claude account switch is already in progress.

What it means

Thrown by beginClaudeAuthSwitch() when the module-level switchInProgress flag is already true. The flag is a process-wide mutex (single boolean) serializing Claude account switches; calling beginClaudeAuthSwitch() a second time before endClaudeAuthSwitch() resets it is rejected. This prevents two concurrent rotations of single-use OAuth refresh tokens.

Source

Thrown at src/main/claude-accounts/live-pty-gate.ts:90

  seededUnconfirmedPtyIds.delete(ptyId)
  persistence?.addClaudeLivePtySessionId(ptyId)
}

export function markClaudePtyExited(ptyId: string): void {
  const hadLivePtys = liveClaudePtyIds.size > 0
  liveClaudePtyIds.delete(ptyId)
  seededUnconfirmedPtyIds.delete(ptyId)
  persistence?.removeClaudeLivePtySessionId(ptyId)
  notifyDrainedOnTransition(hadLivePtys)
}

export function hasLiveClaudePtys(): boolean {
  return liveClaudePtyIds.size > 0
}

export function beginClaudeAuthSwitch(): void {
  if (switchInProgress) {
    throw new Error('A Claude account switch is already in progress.')
  }
  switchInProgress = true
}

export function endClaudeAuthSwitch(): void {
  switchInProgress = false
}

export function isClaudeAuthSwitchInProgress(): boolean {
  return switchInProgress
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Guard the caller with isClaudeAuthSwitchInProgress() before calling beginClaudeAuthSwitch().
  2. Ensure endClaudeAuthSwitch() always runs in a finally block around the switch logic so the flag can never get stuck.
  3. Debounce/coalesce rapid UI switch requests so only one proceeds.
  4. If the flag is stuck true after a crash, surface a 'switch in progress' state to the UI rather than throwing.

Example fix

// before
export function beginClaudeAuthSwitch(): void {
  if (switchInProgress) {
    throw new Error('A Claude account switch is already in progress.')
  }
  switchInProgress = true
}

// after — caller side
beginClaudeAuthSwitch()
try {
  await performSwitch()
} finally {
  endClaudeAuthSwitch()
}
Defensive patterns

Strategy: validation

Validate before calling

if (isClaudeAuthSwitchInProgress()) {
  return { status: 'already-in-progress' }
}
beginClaudeAuthSwitch()

Prevention

When it happens

Trigger: A second UI action (e.g. user double-clicks 'switch account', or an automation fires selectAccount concurrently) invokes beginClaudeAuthSwitch while a prior switch is still running. endClaudeAuthSwitch was not called because the first switch threw before its finally block.

Common situations: Double-click on a switch-account button. Concurrent IPC handlers triggering selection. A prior switch crashed and left switchInProgress stuck true (missing endClaudeAuthSwitch in a finally).

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/829d31f2cd4b2bde. Report an issue: GitHub.