stablyai/orca · warning
mobile pairing timed out
Error message
mobile pairing timed out
What it means
Thrown by the .catch() wrapper around runPairing in startPreProfilePairing (line 101-106). When the timeout timer (setTimeout at line 95) fires it sets timedOut=true and calls dispose(); if runPairing then rejects for ANY reason, the catch swaps the real error for this generic 'mobile pairing timed out' message. The original error is intentionally masked because once the timeout elapsed, the proximate user-facing condition is 'too slow', not whatever internal step happened to fail last.
Source
Thrown at mobile/src/transport/pre-profile-pairing-coordinator.ts:103
if (timer) {
clearTimeout(timer)
timer = null
}
for (const client of clients) {
client.close()
}
clients.clear()
}
timer = setTimeout(() => {
timedOut = true
dispose()
}, args.timeoutMs)
const result = runPairing(args.offer, args.connectOptions, dependencies, clients, () => disposed)
.catch((error: unknown) => {
if (timedOut) {
throw new Error('mobile pairing timed out')
}
throw error
})
.finally(() => {
if (timer) {
clearTimeout(timer)
timer = null
}
for (const client of clients) {
client.close()
}
clients.clear()
})
return {
result,
get timedOut() {
return timedOutView on GitHub (pinned to 1136503c6a)
Solutions
- Increase args.timeoutMs passed to startPreProfilePairing to reflect realistic slow-network ceilings.
- Inspect connection logs ('Relay: cell dial failed', 'sendRequest waited for connect') to identify which phase consumed the budget.
- Ensure the desktop host is awake and the relay invite is not near expiry before initiating pairing.
- If reproducible, wrap individual phases (resolveHostIdentity, saveJournal, racePairingCandidates) with their own shorter timeouts to localize the stall.
Example fix
// before
const attempt = startPreProfilePairing({ offer, timeoutMs: 15_000 })
// after — size budget to the slowest plausible phase sum
const attempt = startPreProfilePairing({
offer,
timeoutMs: 60_000 // host identity + journal + candidate race + 2 RPC round-trips on a slow link
}) Defensive patterns
Strategy: try-catch
Validate before calling
// Before starting, sanity-check the budget against the slowest plausible phase
function isTimeoutMsAdequate(timeoutMs: number): boolean {
// host identity + journal write + candidate race + 2 RPC round-trips
return timeoutMs >= 30_000
} Type guard
function isPairingTimeoutError(error: unknown): boolean {
return error instanceof Error && error.message === 'mobile pairing timed out'
} Try / catch
try {
const { hostId } = await attempt.result
} catch (error) {
if (isPairingTimeoutError(error)) {
showUser('Pairing is taking too long. Check both devices' network and retry.')
return
}
throw error
} Prevention
- Size args.timeoutMs to the sum of plausible slow phases (host identity + journal + candidate race + 2 RPC round-trips), not a default.
- Inspect connection logs during slow pairings to identify which phase is the bottleneck.
- Ensure the desktop is awake and reachable before initiating pairing.
When it happens
Trigger: args.timeoutMs elapsed before runPairing returned a hostId. Any of these during the window causes it: direct+relay candidates both slow to connect (network latency, relay cell migration via recoverThroughDirector), resolveHostIdentity or saveJournal blocked on storage, racePairingCandidates not producing a winner, or provisionRelay/getEndpoints round-trips exceeding the budget.
Common situations: Users on congested/mobile networks where the direct LAN socket and the relay wss handshake both exceed the configured timeoutMs. Also hit when the desktop is asleep (relay invite near inviteExpiresAt) or when AsyncStorage/SecureStore writes are slow under disk pressure.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- ${name} did not emit readiness within ${startupTimeoutMs}ms:
- relay pairing client closed
- mobile pairing cancelled
- Timed out loading check details.
- request timed out after ${timeoutMs / 1000} seconds
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/902b60bf96c08f4d.
Report an issue: GitHub.