{"record":{"id":"6735bce42f662c04","repo":"stablyai/orca","slug":"invalid-relay-hello-6735bc","errorCode":null,"errorMessage":"invalid relay hello","messagePattern":"invalid relay hello","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mobile/src/transport/mobile-relay-physical-client.ts","lineNumber":129,"sourceCode":"      })\n      .catch((error: unknown) => fail(asError(error)))\n  }\n  socket.onerror = () => fail(new Error('relay transport error'))\n  socket.onclose = (event) => fail(new RelayOuterError(event.code || 1006))\n\n  function acceptRelayHello(raw: unknown): void {\n    if (typeof raw !== 'string') {\n      throw new Error('expected plaintext relay hello')\n    }\n    let value: unknown\n    try {\n      value = JSON.parse(raw)\n    } catch {\n      throw new Error('invalid relay hello JSON')\n    }\n    const parsed = RelayPhoneHelloSchema.safeParse(value)\n    if (!parsed.success) {\n      throw new Error('invalid relay hello')\n    }\n    if (!parsed.data.ok) {\n      throw new RelayOuterError(parsed.data.code)\n    }\n    if (parsed.data.credentialKind !== (args.expectedCredentialKind ?? 'invite')) {\n      throw new Error('relay credential resolved as an unexpected credential kind')\n    }\n    outerReady = true\n    log('info', 'Relay: cell accepted credential', 'Starting E2EE handshake')\n    channel.start()\n  }\n\n  function fail(error: Error): void {\n    if (closed) {\n      return\n    }\n    closed = true\n    if (intentionallyClosed) {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/mobile-relay-physical-client.ts#L111-L147","documentation":"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.","triggerScenarios":"The cell sent a 'relay-moved' notice (host reassigned), an error object, or a hello with missing/extra fields under the .strict() schema.","commonSituations":"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.","solutions":["Inspect parsed.error issues from a local safeParse to find the failing field.","Handle relay-moved by re-resolving the endpoint via the resume director.","Align client and cell versions.","Re-derive cellUrl from a fresh pairing offer."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { RelayPhoneHelloSchema } from '../../../src/shared/mobile-relay-phone-protocol'\nfunction isValidHelloJson(raw: string): boolean {\n  try {\n    return RelayPhoneHelloSchema.safeParse(JSON.parse(raw)).success\n  } catch {\n    return false\n  }\n}","typeGuard":"import { RelayPhoneHelloSchema, type RelayPhoneHello } from '../../../src/shared/mobile-relay-phone-protocol'\nfunction isRelayHello(value: unknown): value is RelayPhoneHello {\n  return RelayPhoneHelloSchema.safeParse(value).success\n}","tryCatchPattern":"try {\n  const client = connectMobileRelayForPairing(args)\n} catch (error) {\n  if (error instanceof Error && error.message === 'invalid relay hello') {\n    // re-resolve endpoint in case the cell sent relay-moved\n  }\n}","preventionTips":["Keep the client schema version aligned with the relay cell build.","Distinguish relay-moved from a malformed hello and re-resolve the endpoint for the former.","Log parsed.error issues when diagnosing against a staging cell."],"tags":["relay","websocket","schema","zod","pairing"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}