schollz/croc · error · Error

Sender did not confirm the croc PAKE handshake

Error message

Sender did not confirm the croc PAKE handshake

What it means

Thrown by the recipient when the sender does not answer the 'pake-confirm' message with a 'pake-confirm' of its own. After both sides derive keys, they exchange key-confirmation tokens to prove they derived the same shared key; silence or a wrong message type here means the sender never completed (or corrupted) its half of the handshake, so no encrypted channel is established.

Source

Thrown at web/src/protocol/client.ts:709

    }
    const finished = await wasm().pakeUpdate(pake.handle, peerPake.b);
    const peerKeys = await wasm().derivePeerKeys(
      finished.key,
      peerPake.b2,
      PAKE_PURPOSE_TRANSFER,
      room,
      curve,
      pake.bytes,
      peerPake.b,
    );
    await sendControl(control, {
      t: "pake-confirm",
      v: PAKE_PROTOCOL_VERSION,
      b: peerKeys.confirmationA,
    });
    const confirmationB = await receiveControl(control);
    if (confirmationB.t !== "pake-confirm" || !confirmationB.b) {
      throw new Error("Sender did not confirm the croc PAKE handshake");
    }
    requirePakeVersion(confirmationB.v);
    if (!(await wasm().confirmPeerKey(peerKeys.confirmationB, confirmationB.b))) {
      throw new Error("Sender PAKE confirmation failed");
    }
    key = peerKeys.key;
    data = await openDataConnections(
      settings,
      room,
      dataPorts(relay.banner),
      signal,
    );
    await sendControl(control, {
      t: "externalip",
      m: relay.externalIP,
      b: peerPake.b,
    }, key);
    const peerIP = await receiveControl(control, key);

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Check the sender-side error — the counterpart failure is usually 'Recipient PAKE confirmation failed' or a socket error, which identifies the root cause
  2. Confirm the code phrase is identical on both sides (codeComponents must yield the same room and passphrase)
  3. Retry the transfer; transient relay drops during handshake are common on unstable links
  4. Upgrade both peers to the same protocol version before debugging deeper
Defensive patterns

Strategy: retry

Type guard

function isPakeConfirm(m: { t: string; b?: Uint8Array }): boolean {
  return m.t === "pake-confirm" && !!m.b && m.b.byteLength > 0;
}

Try / catch

catch (e) {
  if (e instanceof Error && e.message === "Sender did not confirm the croc PAKE handshake") {
    // often transient (peer dropped mid-handshake): retry once with a fresh code phrase
  }
  throw e;
}

Prevention

When it happens

Trigger: Sender disconnects after sending its pake reply but before confirmation; sender throws in confirmPeerKey on its side and reports an error control message instead; relay drops or reorders the confirmation frame; incompatible peer that ends the handshake after key derivation.

Common situations: Sender user cancels at the 'Securing channel…' stage; sender's wasm confirmPeerKey fails (wrong passphrase bytes, room mismatch) so it errors out; transient relay disconnection mid-handshake; mock senders that stop after the pake exchange.

Understand the failure class

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/0c69e4bea9860f1b. Report an issue: GitHub.