stablyai/orca · error
expected plaintext relay hello
Error message
expected plaintext relay hello
What it means
Thrown in connectMobileRelayForPairing's acceptRelayHello when the first WebSocket message (raw) is not a string. The relay cell must send a plaintext text frame as the hello; a binary frame at this stage is a protocol violation.
Source
Thrown at mobile/src/transport/mobile-relay-physical-client.ts:119
inboundChain = inboundChain
.then(async () => {
if (closed) {
return
}
if (!outerReady) {
acceptRelayHello(event.data)
return
}
await channel.handleMessage(event.data)
})
.catch((error: unknown) => fail(asError(error)))
}
socket.onerror = () => fail(new Error('relay transport error'))
socket.onclose = (event) => fail(new RelayOuterError(event.code || 1006))
function acceptRelayHello(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 !== (args.expectedCredentialKind ?? 'invite')) {
throw new Error('relay credential resolved as an unexpected credential kind')
}
outerReady = trueView on GitHub (pinned to 1136503c6a)
Solutions
- Verify the relay cell sends a text hello frame per the protocol.
- Check the cell build/version against the client expectation.
- In tests, ensure createSocket mocks emit a string for the first frame.
Defensive patterns
Strategy: try-catch
Type guard
function isTextFrame(raw: unknown): raw is string {
return typeof raw === 'string'
} Try / catch
try {
const client = connectMobileRelayForPairing(args)
} catch (error) {
if (error instanceof Error && error.message === 'expected plaintext relay hello') {
// cell sent a binary first frame; verify cell version, do not retry unchanged
}
} Prevention
- Confirm the relay cell emits a text hello frame per the protocol before relying on it.
- In tests, have createSocket mocks send a string as the first frame.
- Treat a binary first frame as a cell-side defect, not a retryable transient.
When it happens
Trigger: The cell sent an ArrayBuffer/Blob as the first frame instead of a text frame, or a misconfigured cell opened the handshake with binary.
Common situations: A cell version that leads with a binary frame; a middlebox converting text frames to binary; a test createSocket mock sending the wrong type for the first message.
Related errors
- invalid relay hello JSON
- invalid relay hello JSON
- invalid relay hello
- relay_outer_${code}
- relay credential install result does not match pairing journ
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/af78c4712c6cf9ab.
Report an issue: GitHub.