stablyai/orca · error · Error

Need ≥2 terminals to bulk-switch; got ${switchTargets.length

Error message

Need ≥2 terminals to bulk-switch; got ${switchTargets.length}. notes=${notes.join('; ')}

What it means

The bulk-switch phase requires at least two distinct terminal handles to exercise cross-terminal switching under load. The script unions newly-created terminals with already-live ones, dedupes by handle, optionally caps the set, and then asserts >= 2 remain. With fewer than two, the switch amplification would be a degenerate no-op that cannot reproduce the freeze.

Source

Thrown at config/scripts/live-remote-bulk-open-freeze-repro.mjs:190

        (t) => typeof t.handle === 'string' && t.handle.startsWith('term_') && t.connected !== false
      )
      .map((t) => ({ handle: t.handle, title: t.title, worktreeId: t.worktreeId }))
    notes.push(`live terminals listed=${live.length}`)
  } catch (error) {
    notes.push(`terminal list failed: ${String(error).slice(0, 200)}`)
  }

  let switchTargets = [...created.map((c) => c.handle), ...live.map((t) => t.handle)].filter(
    (v, i, a) => typeof v === 'string' && a.indexOf(v) === i
  )

  if (shouldCapSwitchTargets(maxSwitchTargets) && switchTargets.length > maxSwitchTargets) {
    switchTargets = applySwitchTargetCap(switchTargets, maxSwitchTargets)
    amplificationSteps.push(`capped switchTargets=${maxSwitchTargets}`)
  }

  if (switchTargets.length < 2) {
    throw new Error(
      `Need ≥2 terminals to bulk-switch; got ${switchTargets.length}. notes=${notes.join('; ')}`
    )
  }

  amplificationSteps.push(
    `switchTargets=${switchTargets.length} passes=${switchPasses} parallel=${parallel}`
  )
  console.log(
    `[live-freeze] bulk-switching ${switchTargets.length} terminals × ${switchPasses} passes (parallel=${parallel})`
  )

  let maxSwitchMs = 0
  let maxBatchWallMs = 0
  let sumSwitchMs = 0
  let switchCount = 0
  const switchStarted = performance.now()

  for (let pass = 0; pass < switchPasses; pass += 1) {

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Increase createCount so at least two terminals are guaranteed created, or open terminals manually first.
  2. Inspect the joined notes string in the message — it reports list failures and counts that pinpoint whether create or list is the lossy step.
  3. If applySwitchTargetCap is collapsing the set, raise maxSwitchTargets or disable the cap via shouldCapSwitchTargets.
  4. Verify the live terminal handle field name matches what listLiveTerminalHandles reads so dedup keeps the values.

Example fix

// before
const createCount = 0

// after
const createCount = Math.max(2, createCount)
Defensive patterns

Strategy: validation

Validate before calling

if (createCount + liveCount < 2) {
  throw new Error(`Need >=2 terminals for bulk-switch; createCount=${createCount} live=${liveCount}`)
}

Type guard

const hasMinHandles = (arr, n = 2) => Array.isArray(arr) && arr.filter(h => typeof h === 'string').length >= n

Prevention

When it happens

Trigger: createCount is 0 or all create calls failed AND the live terminal list returned zero or one handle; or the cap (maxSwitchTargets) reduced the deduped set below 2; or handles came back as non-strings and were filtered out by the typeof v === 'string' guard.

Common situations: Running with createCount=0 against an idle environment with one open terminal, a remote where terminal creation silently failed, a version mismatch returning handles under a different field name so they all get filtered, or an overly aggressive maxSwitchTargets cap.

Related errors


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