{"record":{"id":"fc31597cb479d85a","repo":"schollz/croc","slug":"recipient-pake-confirmation-failed","errorCode":null,"errorMessage":"Recipient PAKE confirmation failed","messagePattern":"Recipient PAKE confirmation failed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/client.ts","lineNumber":444,"sourceCode":"      PAKE_PURPOSE_TRANSFER,\n      room,\n      curve,\n      peerPake.b,\n      finished.bytes,\n    );\n    await sendControl(control, {\n      t: \"pake\",\n      v: PAKE_PROTOCOL_VERSION,\n      b: finished.bytes,\n      b2: salt,\n    });\n    const confirmationA = await receiveControl(control);\n    if (confirmationA.t !== \"pake-confirm\" || !confirmationA.b) {\n      throw new Error(\"Recipient did not confirm the croc PAKE handshake\");\n    }\n    requirePakeVersion(confirmationA.v);\n    if (!(await wasm().confirmPeerKey(peerKeys.confirmationA, confirmationA.b))) {\n      throw new Error(\"Recipient PAKE confirmation failed\");\n    }\n    await sendControl(control, {\n      t: \"pake-confirm\",\n      v: PAKE_PROTOCOL_VERSION,\n      b: peerKeys.confirmationB,\n    });\n    key = peerKeys.key;\n\n    callbacks.onStatus?.(\"Opening encrypted data channels…\");\n    data = await openDataConnections(\n      settings,\n      room,\n      dataPorts(relay.banner),\n      signal,\n    );\n\n    const peerIP = await receiveControl(control, key);\n    if (peerIP.t !== \"externalip\") throw new Error(\"Recipient did not secure the channel\");","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/client.ts#L426-L462","documentation":"The recipient's key-confirmation bytes failed verification via wasm().confirmPeerKey, meaning the two sides derived different PAKE keys. With the protocol version already matched, the overwhelmingly common cause is that the two parties typed different code phrases. Verification failing here is a security feature: it prevents continuing with mismatched keys.","triggerScenarios":"Sender and recipient using different secrets for the same room (typo on either side); one party pasting the code with an extra or missing word; auto-correct altering one side's phrase.","commonSituations":"Manually transcribed codes over voice/chat; trailing whitespace or newline appended on paste on one end only; recipient joining with an old code after the sender regenerated.","solutions":["Re-share the exact same code phrase to both sides (copy-paste, not retype) and retry","Strip surrounding whitespace when reading the code into the client","Prefer the auto-generated code phrase over custom codes to avoid transcription errors"],"exampleFix":"// before\nconst secret = codeInput.value; // \"nice-owl-atom-lamp\\n\" on recipient\n\n// after\nconst secret = codeInput.value.trim();\nawait sendFiles({ files, secret, settings });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await sendFiles(opts);\n} catch (e) {\n  if (/PAKE confirmation failed/.test(e.message)) {\n    setCodeError(\"The code does not match the recipient's code. Re-share it and retry.\");\n    return; // do NOT retry with the same code automatically\n  }\n  throw e;\n}","preventionTips":["Copy-paste the code between parties instead of retyping it","Trim whitespace on both send and receive inputs","Treat this error as a wrong passphrase; never auto-retry the same secret"],"tags":["pake","passphrase-mismatch","security","handshake"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}