{"record":{"id":"4529e60975116280","repo":"schollz/croc","slug":"recipient-did-not-start-a-croc-pake-handshake","errorCode":null,"errorMessage":"Recipient did not start a croc PAKE handshake","messagePattern":"Recipient did not start a croc PAKE handshake","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/client.ts","lineNumber":410,"sourceCode":"  const { room, passphrase } = await wasm().codeComponents(secret);\n  let control: CrocSocket | undefined;\n  let data: CrocSocket[] = [];\n  let key: Uint8Array | undefined;\n  try {\n    callbacks.onStatus?.(\"Connecting to relay…\");\n    const relay = await connectRelay(\n      settings,\n      room,\n      controlPort(settings.relayAddress),\n      signal,\n    );\n    control = relay.socket;\n    callbacks.onStatus?.(\"Waiting for recipient…\");\n    await waitForHandshake(control, room, passphrase, signal);\n\n    const peerPake = await receiveControl(control);\n    if (peerPake.t !== \"pake\" || !peerPake.b || !peerPake.b2) {\n      throw new Error(\"Recipient did not start a croc PAKE handshake\");\n    }\n    requirePakeVersion(peerPake.v);\n    const curve = textDecoder.decode(peerPake.b2);\n    const pake = await wasm().pakeInitWithIdentities(\n      textEncoder.encode(passphrase),\n      1,\n      curve,\n      PAKE_PURPOSE_TRANSFER,\n      room,\n    );\n    const finished = await wasm().pakeUpdate(pake.handle, peerPake.b);\n    const salt = randomBytes(PAKE_SALT_SIZE);\n    const peerKeys = await wasm().derivePeerKeys(\n      finished.key,\n      salt,\n      PAKE_PURPOSE_TRANSFER,\n      room,\n      curve,","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/client.ts#L392-L428","documentation":"On the sender side, after the relay room is joined the first control message from the recipient must be of type 'pake' with both b (PAKE bytes) and b2 (curve name) present. Anything else means the recipient did not begin the croc PAKE handshake as expected, e.g. an error frame, a probe, or a client speaking a different message order.","triggerScenarios":"The recipient being a different croc version that sends another message type first; the recipient sending a relay 'error' or leaving the room so the received frame is not 'pake'; connecting with the wrong code so the peer in the room is a different transfer's participant.","commonSituations":"Version skew between the two web/CLI clients; code-phrase collisions putting two different transfers in one room; recipient cancelling right at handshake time.","solutions":["Confirm both parties use the same transfer code and compatible croc versions","Retry the transfer end-to-end with a freshly generated code","If it persists, log the actual message type received to identify the divergent peer"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isPakeMessage(msg) {\n  return !!msg && msg.t === \"pake\" && msg.b instanceof Uint8Array && msg.b2 instanceof Uint8Array;\n}","tryCatchPattern":"try {\n  await sendFiles(opts);\n} catch (e) {\n  if (/did not start a croc PAKE handshake/.test(e.message)) {\n    showBanner(\"Recipient could not handshake. Retry with a fresh code.\");\n    return;\n  }\n  throw e;\n}","preventionTips":["Keep both endpoints on matching croc versions","Start transfers with freshly generated codes to avoid room collisions","Log message.t on failure to identify divergent peer implementations"],"tags":["pake","handshake","sender","protocol"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}