stablyai/orca · error

invalid relay hello

Error message

invalid relay hello

What it means

Thrown in connectMobileRelayForPairing's acceptRelayHello when the parsed JSON does not satisfy RelayPhoneHelloSchema. The cell sent a JSON frame that is not a valid relay-hello during the pairing dial.

Source

Thrown at mobile/src/transport/mobile-relay-physical-client.ts:129

      })
      .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 = true
    log('info', 'Relay: cell accepted credential', 'Starting E2EE handshake')
    channel.start()
  }

  function fail(error: Error): void {
    if (closed) {
      return
    }
    closed = true
    if (intentionallyClosed) {

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Inspect parsed.error issues from a local safeParse to find the failing field.
  2. Handle relay-moved by re-resolving the endpoint via the resume director.
  3. Align client and cell versions.
  4. Re-derive cellUrl from a fresh pairing offer.
Defensive patterns

Strategy: try-catch

Validate before calling

import { RelayPhoneHelloSchema } from '../../../src/shared/mobile-relay-phone-protocol'
function isValidHelloJson(raw: string): boolean {
  try {
    return RelayPhoneHelloSchema.safeParse(JSON.parse(raw)).success
  } catch {
    return false
  }
}

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 client = connectMobileRelayForPairing(args)
} catch (error) {
  if (error instanceof Error && error.message === 'invalid relay hello') {
    // re-resolve endpoint in case the cell sent relay-moved
  }
}

Prevention

When it happens

Trigger: The cell sent a 'relay-moved' notice (host reassigned), an error object, or a hello with missing/extra fields under the .strict() schema.

Common situations: Client/cell version skew changing the hello shape; the endpoint URL reached the wrong relay service; the host was reassigned so the cell advertises relay-moved.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/6735bce42f662c04. Report an issue: GitHub.