gchq/CyberChef · error · OperationError
Not a Client Hello.
Error message
Not a Client Hello.
What it means
JA3Fingerprint reads the handshake type byte (first byte of the handshake body) and requires 1 (ClientHello). A ServerHello (type 2) or any other handshake type (Certificate, ServerKeyExchange, etc.) throws. readInt returning undefined on short input also makes the !== check true.
Source
Thrown at src/core/operations/JA3Fingerprint.mjs:77
input = Utils.convertToByteArray(input, inputFormat);
const s = new Stream(new Uint8Array(input));
const handshake = s.readInt(1);
if (handshake !== 0x16)
throw new OperationError("Not handshake data.");
// Version
s.moveForwardsBy(2);
// Length
const length = s.readInt(2);
if (s.length !== length + 5)
throw new OperationError("Incorrect handshake length.");
// Handshake type
const handshakeType = s.readInt(1);
if (handshakeType !== 1)
throw new OperationError("Not a Client Hello.");
// Handshake length
const handshakeLength = s.readInt(3);
if (s.length !== handshakeLength + 9)
throw new OperationError("Not enough data in Client Hello.");
// Hello version
const helloVersion = s.readInt(2);
// Random
s.moveForwardsBy(32);
// Session ID
const sessionIDLength = s.readInt(1);
s.moveForwardsBy(sessionIDLength);
// Cipher suites
const cipherSuitesLength = s.readInt(2);View on GitHub (pinned to 4290ea7539)
Solutions
- For a ServerHello, use JA3S Fingerprint, not JA3.
- Confirm the record you fed is actually a ClientHello (type byte === 1).
- Re-slice so parsing starts at the record content-type byte.
- Match inputFormat to the real data so the type byte is correct.
Example fix
// before ja3.run(serverHelloRecord, ['Hex','Base64']); // type byte 2 -> Not a Client Hello. // after ja3s.run(serverHelloRecord, ['Hex','Base64']); // use the Server Hello op
Defensive patterns
Strategy: validation
Validate before calling
import Utils from "src/core/Utils.mjs";
function assertClientHello(input, inputFormat) {
const b = Utils.convertToByteArray(input, inputFormat);
if (b.length < 6) throw new Error('record too short');
if (b[5] !== 1) {
throw new Error(`Handshake type ${b[5]} is not ClientHello (1). For ServerHello use JA3S.`);
}
return b;
} Type guard
function isClientHello(bytes) {
return bytes.length >= 6 && bytes[0] === 0x16 && bytes[5] === 1;
} Prevention
- Use JA3 only on ClientHello (type 1); use JA3S for ServerHello.
- Confirm the type byte before running.
- Re-slice so parsing starts at the content-type byte.
- Match inputFormat to the real data.
When it happens
Trigger: The record is a ServerHello or another handshake message rather than a ClientHello; you fed JA3 a server-side capture. Also when inputFormat mismatch makes the type byte garbage, or when reading started one byte off (the byte after content-type was consumed).
Common situations: Using JA3 (client) on a server capture instead of JA3S; off-by-one slicing; inputFormat mismatch; feeding a Certificate/ServerHello record.
Related errors
- Not handshake data.
- Incorrect handshake length.
- Not enough data in Client Hello.
- Not handshake data.
- Incorrect handshake length.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/0c87bdd2968c1d2a.
Report an issue: GitHub.