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
- Check the sender-side error — the counterpart failure is usually 'Recipient PAKE confirmation failed' or a socket error, which identifies the root cause
- Confirm the code phrase is identical on both sides (codeComponents must yield the same room and passphrase)
- Retry the transfer; transient relay drops during handshake are common on unstable links
- 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
- Retry handshake failures with a new code phrase before investigating deeper
- Check the peer side first — its error names the actual failure (often confirmPeerKey)
- Keep handshakes short: long gaps between pake and confirm invite relay timeouts
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Recipient PAKE confirmation failed
- Sender did not complete the croc PAKE handshake
- Sender provided an invalid ${peerPake.b2.byteLength}-byte PA
- Sender PAKE confirmation failed
- Sender did not secure the channel
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/0c69e4bea9860f1b.
Report an issue: GitHub.