stablyai/orca · error · Error

Need ≥2 terminals; got ${openTargets.length}. ${notes.join('

Error message

Need ≥2 terminals; got ${openTargets.length}. ${notes.join('; ')}

What it means

Realistic-freeze repro requires at least two distinct terminal handles for its open/switch exercise. It unions created terminal handles with live ones, dedupes, then asserts length >= 2. Below that, the open/park/switch phases cannot meaningfully run.

Source

Thrown at config/scripts/live-remote-realistic-freeze-repro.mjs:229

    )
    phases.push({ phase: 'seed-flood', created: created.length })
  }

  // Prefer created floods for open pass; fill with existing live terminals.
  let live = []
  try {
    live = listLiveTerminalHandles()
    notes.push(`live terminals listed=${live.length}`)
  } catch (error) {
    notes.push(`terminal list failed: ${String(error).slice(0, 200)}`)
  }

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

  if (openTargets.length < 2) {
    throw new Error(`Need ≥2 terminals; got ${openTargets.length}. ${notes.join('; ')}`)
  }

  const openList = openTargets.slice(0, Math.min(openCount, openTargets.length))

  // --- Phase: park — leave one session focused, rest accumulate flood while "away" ---
  try {
    const parkHandle = openList[0]
    const parked = await orcaJsonAsync(['terminal', 'switch', '--terminal', parkHandle], {
      timeoutMs: 60_000
    })
    notes.push(`park switch ms=${parked.elapsedMs.toFixed(0)} handle=${parkHandle}`)
  } catch (error) {
    notes.push(`park switch failed: ${String(error).slice(0, 200)}`)
  }

  console.log(`[realistic-freeze] idle ${idleMs}ms while remotes stream (user away / asleep)`)
  const idleStarted = performance.now()
  await sleep(idleMs)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Set createCount >= 2 (or pre-open terminals) so the union yields at least two handles.
  2. Inspect the notes joined into the message — it records 'terminal list failed' and list counts that show whether list or create is the loss.
  3. Verify listLiveTerminalHandles reads the correct handle field for the remote orca version.

Example fix

// before
if (openTargets.length < 2) {
  throw new Error(`Need >=2 terminals; got ${openTargets.length}. ${notes.join('; ')}`)
}

// after
if (openTargets.length < 2) {
  throw new Error(`Need >=2 terminals; got ${openTargets.length}. created=${created.length} live=${live.length}. ${notes.join('; ')}`)
}
Defensive patterns

Strategy: validation

Validate before calling

if (createCount + live.length < 2) {
  throw new Error(`Need >=2 terminals; create=${createCount} live=${live.length}`)
}

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 creates failed and the live list returned < 2 handles; or the live-list call itself failed (caught and pushed to notes) leaving only the created set.

Common situations: Idle remote with a single terminal, terminal creation failing under load, a live-list field-name mismatch filtering all handles out, or running the open phase before any terminals exist.

Related errors


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