stablyai/orca · error · Error

Unexpected helper handshake: ${JSON.stringify(capabilities)}

Error message

Unexpected helper handshake: ${JSON.stringify(capabilities)}

What it means

After the helper appears, the sidecar's capabilities RPC must report protocolVersion === 1. Any other value (or a capabilities object missing protocolVersion, caught by the optional chain) means the helper speaks a different protocol version than this benchmark expects, so the session is not 'authenticated' in the sense the test relies on. The full capabilities payload is serialized into the message.

Source

Thrown at config/scripts/macos-computer-helper-owner-loss-benchmark.mjs:276

  const sidecar = startSidecar()
  let helper
  try {
    const capabilitiesResult = requestSidecar(sidecar, 1, 'capabilities').then(
      (capabilities) => ({ capabilities }),
      (error) => ({ error })
    )
    helper = await waitForHelper(sidecar.child.pid)
    const helperRecordPath = process.env[HELPER_RECORD_PATH_ENV]
    if (!helperRecordPath) {
      throw new Error('Missing helper process record path')
    }
    writeProcessRecord(helperRecordPath, helper)
    const { capabilities, error } = await capabilitiesResult
    if (error) {
      throw error
    }
    if (capabilities?.protocolVersion !== 1) {
      throw new Error(`Unexpected helper handshake: ${JSON.stringify(capabilities)}`)
    }
    return { authenticated: capabilities.protocolVersion === 1, sidecar, helper }
  } catch (error) {
    sidecar.child.kill('SIGKILL')
    await stopProcess(helper)
    throw error
  }
}

async function exerciseActiveRequests(sidecar) {
  const latencies = []
  const startedAt = performance.now()
  for (let index = 0; index < ACTIVE_REQUEST_COUNT; index += 1) {
    const requestStartedAt = performance.now()
    const result = await requestSidecar(sidecar, 10_000 + index, 'listApps')
    if (!Array.isArray(result?.apps)) {
      throw new Error(`Unexpected listApps response: ${JSON.stringify(result)}`)
    }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Read protocolVersion from the JSON in the message to see what the helper actually reported.
  2. Align helper and sidecar to the same release so both speak protocolVersion 1.
  3. If the protocol was intentionally bumped, update the benchmark's expected version constant from 1.

Example fix

// before
if (capabilities?.protocolVersion !== 1) {
  throw new Error(`Unexpected helper handshake: ${JSON.stringify(capabilities)}`)
}

// after
const EXPECTED_PROTOCOL = 1
if (capabilities?.protocolVersion !== EXPECTED_PROTOCOL) {
  throw new Error(`Helper protocol ${capabilities?.protocolVersion} != expected ${EXPECTED_PROTOCOL}: ${JSON.stringify(capabilities)}`)
}
Defensive patterns

Strategy: validation

Validate before calling

const EXPECTED_PROTOCOL = 1
if (capabilities?.protocolVersion !== EXPECTED_PROTOCOL) {
  throw new Error(`Helper protocol ${capabilities?.protocolVersion} != ${EXPECTED_PROTOCOL}`)
}

Type guard

const isExpectedHandshake = (c, expected = 1) => c?.protocolVersion === expected

Try / catch

try {
  await startAuthenticatedSession()
} catch (e) {
  if (/Unexpected helper handshake/.test(e.message)) { /* align helper/sidecar versions, rerun */ }
  throw e
}

Prevention

When it happens

Trigger: A newer or older helper binary whose protocolVersion is 2/0/undefined, a capabilities response that failed and surfaced as error (re-thrown first), or a sidecar that returned an unexpected envelope shape.

Common situations: Helper/sidecar version skew (one updated without the other), a local helper build with a bumped protocol version, or a regression where capabilities omits protocolVersion.

Understand the failure class

Related errors


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