stablyai/orca · error

relay pairing RPC unavailable after relay path authenticatio

Error message

relay pairing RPC unavailable after relay path authentication

What it means

Thrown in runPairing after winner.client.sendRequest('pairing.provisionRelay') returned a JSON-RPC method_not_found error AND the winning candidate path was 'relay' (not 'direct'). The coordinator tolerates a missing provisionRelay on the direct path (line 224-227, for older desktops that predate relay support), but a relay-path winner that lacks provisionRelay is unrecoverable: the relay was authenticated yet the desktop cannot mint the durable relay credential, so the pairing cannot proceed to getEndpoints.

Source

Thrown at mobile/src/transport/pre-profile-pairing-coordinator.ts:223

    return { hostId }
  }

  journal = {
    ...journal,
    metadata: {
      ...journal.metadata,
      winner: winner.path,
      authorizationMode: winner.path === 'direct' ? 'authenticated-direct' : 'relay-basis'
    }
  }
  await dependencies.updateJournal(journal.metadata.journalId, () => journal!.metadata)
  const provision = await winner.client.sendRequest('pairing.provisionRelay', {
    reqId: journal.metadata.installReqId,
    newResumeTokenHash: journal.metadata.pendingResumeTokenHash
  })
  if (isMethodNotFound(provision)) {
    if (winner.path !== 'direct') {
      throw new Error('relay pairing RPC unavailable after relay path authentication')
    }
    await dependencies.saveHost(baseHost(offer, hostId, hostName, now))
    await dependencies.clearJournal(journal.metadata.journalId)
    return { hostId }
  }
  const installed = DeviceCredentialInstalledSchema.parse(requireSuccess(provision))
  const endpoints = PairingGetEndpointsResultSchema.parse(
    requireSuccess(
      await winner.client.sendRequest('pairing.getEndpoints', {
        installReqId: journal.metadata.installReqId
      })
    )
  )
  assertCommittedInstall(endpoints.installStatus, installed)
  if (!endpoints.relay) {
    throw new Error('desktop returned no relay endpoint after credential install')
  }
  assertActive(isDisposed)

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Upgrade the desktop Orca runtime to a version that implements 'pairing.provisionRelay' (it must ship alongside relay transport support).
  2. If a legacy desktop must be supported, force the direct path by ensuring the relay candidate loses the race (e.g., withhold offer.relay) so winner.path === 'direct' takes the tolerant branch at line 224.
  3. Verify the desktop's RPC method registry exposes 'pairing.provisionRelay' before advertising relay capability to mobile clients.

Example fix

// before — relay-capable offer sent to a desktop lacking provisionRelay
const offer = { ...base, relay: relayEndpoint }

// after — direct-only until desktop is upgraded
const offer = { ...base /* no relay */ }
Defensive patterns

Strategy: validation

Validate before calling

// Before advertising relay, confirm the desktop implements provisionRelay
async function desktopSupportsProvisionRelay(client: PairingCandidateClient): Promise<boolean> {
  const probe = await client.sendRequest('rpc.methods', {})
  if (!probe.ok) return false
  const methods = (probe.result as { methods?: string[] }).methods ?? []
  return methods.includes('pairing.provisionRelay')
}

Type guard

function isRelayProvisionUnavailable(error: unknown): boolean {
  return error instanceof Error
    && error.message === 'relay pairing RPC unavailable after relay path authentication'
}

Try / catch

try {
  await runPairing(...)
} catch (error) {
  if (isRelayProvisionUnavailable(error)) {
    // retry without relay so the direct path takes the tolerant branch
    return startPreProfilePairing({ ...args, offer: { ...args.offer, relay: undefined } })
  }
  throw error
}

Prevention

When it happens

Trigger: A relay-path winner (racePairingCandidates returned { path: 'relay', client }) dialing a desktop whose RPC surface does not implement 'pairing.provisionRelay' — i.e., an older Orca desktop version that happens to still accept relay transport but lacks the credential-install RPC. isMethodNotFound(provision) is true AND winner.path === 'relay'.

Common situations: Version skew: mobile client newer than the desktop, where the desktop exposes relay transport but predates the provisionRelay RPC. Rare in normal operation because relay transport and provisionRelay shipped together; appears in partial upgrades, custom desktop builds, or against a mock/test desktop that implements some pairing RPCs but not provisionRelay.

Understand the failure class

Related errors


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