schollz/croc · error · Error
Recipient did not start a croc PAKE handshake
Error message
Recipient did not start a croc PAKE handshake
What it means
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.
Source
Thrown at web/src/protocol/client.ts:410
const { room, passphrase } = await wasm().codeComponents(secret);
let control: CrocSocket | undefined;
let data: CrocSocket[] = [];
let key: Uint8Array | undefined;
try {
callbacks.onStatus?.("Connecting to relay…");
const relay = await connectRelay(
settings,
room,
controlPort(settings.relayAddress),
signal,
);
control = relay.socket;
callbacks.onStatus?.("Waiting for recipient…");
await waitForHandshake(control, room, passphrase, signal);
const peerPake = await receiveControl(control);
if (peerPake.t !== "pake" || !peerPake.b || !peerPake.b2) {
throw new Error("Recipient did not start a croc PAKE handshake");
}
requirePakeVersion(peerPake.v);
const curve = textDecoder.decode(peerPake.b2);
const pake = await wasm().pakeInitWithIdentities(
textEncoder.encode(passphrase),
1,
curve,
PAKE_PURPOSE_TRANSFER,
room,
);
const finished = await wasm().pakeUpdate(pake.handle, peerPake.b);
const salt = randomBytes(PAKE_SALT_SIZE);
const peerKeys = await wasm().derivePeerKeys(
finished.key,
salt,
PAKE_PURPOSE_TRANSFER,
room,
curve,View on GitHub (pinned to e25f1bdc04)
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
Defensive patterns
Strategy: try-catch
Type guard
function isPakeMessage(msg) {
return !!msg && msg.t === "pake" && msg.b instanceof Uint8Array && msg.b2 instanceof Uint8Array;
} Try / catch
try {
await sendFiles(opts);
} catch (e) {
if (/did not start a croc PAKE handshake/.test(e.message)) {
showBanner("Recipient could not handshake. Retry with a fresh code.");
return;
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Version skew between the two web/CLI clients; code-phrase collisions putting two different transfers in one room; recipient cancelling right at handshake time.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Peer sent an unexpected control handshake
- Recipient did not confirm the croc PAKE handshake
- Recipient did not secure the channel
- Sender did not complete the croc PAKE handshake
- Sender did not secure the channel
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/4529e60975116280.
Report an issue: GitHub.