stablyai/orca · error
desktop returned no relay endpoint after credential install
Error message
desktop returned no relay endpoint after credential install
What it means
Thrown in runPairing after a successful provisionRelay when the follow-up pairing.getEndpoints response parsed cleanly (PairingGetEndpointsResultSchema) but its `relay` field is falsy. The desktop installed the credential (assertCommittedInstall passed) yet did not publish the relay endpoint the mobile side needs to persist a relay-capable host profile. Without endpoints.relay there is no relayHost to save (relayWebSocketUrl at line 278-282 needs relay.cellUrl and relayHostId), so pairing cannot complete.
Source
Thrown at mobile/src/transport/pre-profile-pairing-coordinator.ts:239
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)
await dependencies.writeCredentialBundle(promotePairingJournalCredential({ journal, installed }))
await dependencies.saveHost(relayHost(journal, endpoints.relay))
await dependencies.clearJournal(journal.metadata.journalId)
return { hostId }
}
function baseHost(
offer: PairingOffer,
hostId: string,
name: string,
lastConnected: number
): HostProfile {
return {
id: hostId,
name,
endpoint: offer.endpoint,View on GitHub (pinned to 1136503c6a)
Solutions
- On the desktop, verify relay endpoint publication is enabled and that getEndpoints returns a non-null relay after provisionRelay commits.
- Inspect the desktop logs around the provisionRelay→getEndpoints sequence for relay-publishing errors or skipped steps.
- If relay is intentionally disabled on the desktop, pair without offer.relay so the flow takes the direct-only branch (line 203-206) and never calls getEndpoints.
- Reproduce by calling pairing.getEndpoints directly against the desktop immediately after provisionRelay to confirm the omission.
Defensive patterns
Strategy: validation
Validate before calling
// After getEndpoints, verify relay is present before relying on it
function hasRelayEndpoint(endpoints: unknown): endpoints is { relay: MobileRelayEndpoint } {
return typeof endpoints === 'object' && endpoints !== null && 'relay' in endpoints && !!endpoints.relay
} Type guard
function isNoRelayEndpointError(error: unknown): boolean {
return error instanceof Error
&& error.message === 'desktop returned no relay endpoint after credential install'
} Try / catch
try {
await runPairing(...)
} catch (error) {
if (isNoRelayEndpointError(error)) {
// desktop didn't publish relay — re-pair without relay to save a direct-only host
return startPreProfilePairing({ ...args, offer: { ...args.offer, relay: undefined } })
}
throw error
} Prevention
- On the desktop, ensure relay endpoint publication is enabled whenever provisionRelay is implemented.
- If relay is intentionally disabled, pair without offer.relay to avoid reaching getEndpoints.
- Monitor desktop logs for the provisionRelay→getEndpoints sequence to catch silent omissions.
When it happens
Trigger: Desktop returned { ok: true, result: { installStatus: { state:'committed', result }, relay: null } } (or omitted relay). assertCommittedInstall(endpoints.installStatus, installed) already passed, so install is consistent — only the endpoint advertisement is missing. Caused by server-side logic that provisions credentials but skips/defers relay endpoint publication, or a desktop config that disabled relay publishing post-install.
Common situations: Hits after a desktop-side change to relay endpoint configuration (relay disabled in host settings but credential install still succeeds), or against a desktop build where getEndpoints omits relay under certain feature flags. Mobile users see pairing fail at the very last step after a long successful handshake.
Related errors
- relay pairing client closed
- relay pairing RPC unavailable after relay path authenticatio
- relay credential install was not authoritatively reconciled
- relay credential install result does not match pairing journ
- ${response.error.code}: ${response.error.message}
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/6968519efd6d72d8.
Report an issue: GitHub.