stablyai/orca · error
invalid relay hello
Error message
invalid relay hello
What it means
Thrown when RelayPhoneHelloSchema.safeParse(value) fails: the first frame parsed as JSON but does not match the relay-hello union (type literal 'relay-hello', ok flag, credentialKind 'invite'|'resume', leaseExpiresAt, and for resume the acceptedCredentialVersion/acceptedAs/resumeExpiresAt fields).
Source
Thrown at mobile/src/transport/mobile-relay-e2ee-link.ts:118
.catch((error: unknown) => this.fail(asError(error)))
}
this.socket.onerror = () => this.fail(new Error('relay transport error'))
this.socket.onclose = (event) => this.fail(new RelayOuterError(event.code || 1006))
}
private acceptHello(raw: unknown): void {
if (typeof raw !== 'string') {
throw new Error('expected plaintext relay hello')
}
let value: unknown
try {
value = JSON.parse(raw)
} catch {
throw new Error('invalid relay hello JSON')
}
const parsed = RelayPhoneHelloSchema.safeParse(value)
if (!parsed.success) {
throw new Error('invalid relay hello')
}
if (!parsed.data.ok) {
throw new RelayOuterError(parsed.data.code)
}
if (parsed.data.credentialKind !== this.options.expectedCredentialKind) {
throw new Error('relay credential resolved as an unexpected credential kind')
}
this.outerReady = true
this.options.onHello?.(parsed.data)
this.channel.start()
}
private fail(error: Error): void {
if (this.closed) {
return
}
this.closed = true
this.channel.dispose()View on GitHub (pinned to 1136503c6a)
Solutions
- Capture parsed.error.issues from a local safeParse to see which field failed.
- If the frame is relay-moved, re-resolve the endpoint via the resume director before reconnecting.
- Align client and relay-cell versions so the hello schema matches.
- Verify cellUrl and relayHostId target the intended cell.
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-validate a captured frame against the same schema the cell should use
import { RelayPhoneHelloSchema } from '../../../src/shared/mobile-relay-phone-protocol'
const ok = RelayPhoneHelloSchema.safeParse(JSON.parse(capturedFrame)).success Type guard
import { RelayPhoneHelloSchema, type RelayPhoneHello } from '../../../src/shared/mobile-relay-phone-protocol'
function isRelayHello(value: unknown): value is RelayPhoneHello {
return RelayPhoneHelloSchema.safeParse(value).success
} Try / catch
try {
const link = new MobileRelayE2eeLink(options)
} catch (error) {
if (error instanceof Error && error.message === 'invalid relay hello') {
// re-resolve endpoint via director in case the cell sent relay-moved
}
} Prevention
- Keep the client's mobile-relay-phone-protocol schema version in lockstep with the relay cell build.
- Handle relay-moved distinctly from a malformed hello by re-resolving the endpoint.
- Log parsed.error issues when reproducing against a staging cell.
When it happens
Trigger: The cell sent valid JSON that is not a relay-hello: a 'relay-moved' notice (host reassigned to a new cellUrl), an error object, or a hello missing/adding required fields under the .strict() schema.
Common situations: Client/cell version skew where a newer cell changed the hello shape; the host was reassigned and the cell advertises relay-moved instead of relay-hello; the endpoint URL reached a different relay service that speaks another protocol.
Related errors
- invalid relay hello
- invalid relay hello JSON
- relay_outer_${code}
- Invalid accounts snapshot from host
- E2EE device authentication rejected
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/87ca003f6e3abaff.
Report an issue: GitHub.