stablyai/orca · error · Error
relay credential rotation endpoint state missing
Error message
relay credential rotation endpoint state missing
What it means
Thrown near the end of `rotateMobileRelayCredential` when `endpoints.relay` is missing or the install is not in `committed` state. Even if `provisionRelay` succeeded, the rotation cannot complete without an authoritative relay endpoint to publish alongside the credential.
Source
Thrown at mobile/src/transport/mobile-relay-credential-rotation.ts:69
const response = await args.client.sendRequest('pairing.provisionRelay', {
reqId: pending.reqId,
newResumeTokenHash: pending.hash,
expectedCurrentHash: bundle.current.hash
})
if (!response.ok) {
throw new Error(`${response.error.code}: ${response.error.message}`)
}
const installed = DeviceCredentialInstalledSchema.parse(response.result)
endpoints = await getEndpoints(args.client, pending.reqId)
if (
endpoints.installStatus?.state !== 'committed' ||
JSON.stringify(endpoints.installStatus.result) !== JSON.stringify(installed)
) {
throw new Error('relay credential rotation was not authoritatively committed')
}
}
if (!endpoints.relay || endpoints.installStatus?.state !== 'committed') {
throw new Error('relay credential rotation endpoint state missing')
}
const installed = endpoints.installStatus.result
const next = MobileRelayCredentialBundleSchema.parse({
...bundle,
current: {
token: pending.token,
hash: pending.hash,
version: installed.currentVersion,
expiresAt: installed.resumeExpiresAt
},
...(installed.graceExpiresAt
? { grace: { ...bundle.current, expiresAt: installed.graceExpiresAt } }
: { grace: undefined }),
pending: undefined
})
await args.writeBundle(next)
return { bundle: next, relay: endpoints.relay }
}View on GitHub (pinned to 1136503c6a)
Solutions
- Retry `getEndpoints` after a delay to allow the relay cell to be allocated.
- If `relay` is persistently absent, surface a relay-unavailable error to the user and keep the prior credential.
- Verify with the server operator that relay provisioning is healthy.
Example fix
// before
// proceeds to writeBundle with undefined relay -> throws
// after
for (let i = 0; i < 3 && (!endpoints.relay || endpoints.installStatus?.state !== 'committed'); i++) {
await delay(500)
endpoints = await getEndpoints(args.client, pending.reqId)
}
if (!endpoints.relay) throw new Error('relay endpoint never allocated') Defensive patterns
Strategy: retry
Validate before calling
// Probe for relay presence before promoting:
const endpoints = await getEndpoints(client, pending.reqId)
if (!endpoints.relay) { await delay(500); /* re-check */ } Type guard
function hasRelayEndpoint(e: { relay?: unknown }): boolean { return !!e.relay } Try / catch
try { return await rotateMobileRelayCredential(args) } catch (e) { if (e.message === 'relay credential rotation endpoint state missing') { scheduleRetry(args); return null } throw e } Prevention
- Retry getEndpoints a few times to allow relay cell allocation.
- Keep the previous credential intact until the new one is fully confirmed.
- Surface relay-unavailable distinctly so users retry later.
When it happens
Trigger: Server returned `committed` install status but no `relay` endpoint object; install reverted to a non-committed state between the two `getEndpoints` calls; server allocated the credential but not the relay cell.
Common situations: Partial server-side provisioning; a relay cell that was deallocated; misconfigured relay that reports install success without a routable endpoint.
Related errors
- relay credential rotation was not authoritatively committed
- relay credential install result does not match pairing journ
- relay credential rotation pending state missing
- ${response.error.code}: ${response.error.message}
- direct pairing upgrade was not authoritatively committed
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/0980055f43c6afc1.
Report an issue: GitHub.