gchq/CyberChef · error · OperationError
Not enough data in Client Hello.
Error message
Not enough data in Client Hello.
What it means
JA3Fingerprint reads the 3-byte handshake length and requires total stream length === handshakeLength + 9 (5 record header + 4 handshake header). A mismatch means the ClientHello body is truncated or carries extra/missing bytes. readInt returning undefined on short input also satisfies the !== check.
Source
Thrown at src/core/operations/JA3Fingerprint.mjs:82
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);
const cipherSuites = s.getBytes(cipherSuitesLength);
const cs = new Stream(cipherSuites);
const cipherSegment = parseJA3Segment(cs, 2);
// Compression MethodsView on GitHub (pinned to 4290ea7539)
Solutions
- Ensure the full ClientHello body is present (handshakeLength bytes after the 4-byte handshake header).
- Match inputFormat so the 3-byte handshake length field is correct.
- Re-capture the ClientHello including all extensions.
- Trim the input to exactly handshakeLength + 9 bytes.
Example fix
// before ja3.run(truncatedClientHello, ['Hex','Base64']); // length mismatch -> Not enough data. // after const full = await recaptureFullClientHello(); ja3.run(full, ['Hex','Base64']);
Defensive patterns
Strategy: validation
Validate before calling
import Utils from "src/core/Utils.mjs";
function assertFullClientHello(input, inputFormat) {
const b = Utils.convertToByteArray(input, inputFormat);
if (b.length < 9) throw new Error('record too short for handshake header');
const hsLen = (b[6] << 16) | (b[7] << 8) | b[8];
if (b.length !== hsLen + 9) {
throw new Error(`Stream length ${b.length} != handshake length ${hsLen}+9. ClientHello is truncated or has extra bytes.`);
}
return b;
} Type guard
function isCompleteClientHello(bytes) {
if (bytes.length < 9) return false;
const hsLen = (bytes[6] << 16) | (bytes[7] << 8) | bytes[8];
return bytes[0] === 0x16 && bytes[5] === 1 && bytes.length === hsLen + 9;
} Prevention
- Ensure the full ClientHello body (incl. extensions) is present.
- Match inputFormat so the 3-byte length is correct.
- Re-capture if extensions are missing.
- Trim input to exactly handshakeLength + 9 bytes.
When it happens
Trigger: A truncated ClientHello (missing extensions/body), a record whose handshake length field is corrupted by an inputFormat mismatch, or extra bytes beyond the handshake body but inside the declared record length. Session ID / cipher suite / extension parsing has not yet started, so the failure is purely about total size.
Common situations: Truncated paste of a ClientHello, capture missing the extensions tail, inputFormat mismatch corrupting the 3-byte length, or a record that includes padding the parser does not account for.
Related errors
- Not handshake data.
- Incorrect handshake length.
- Not a Client Hello.
- Not handshake data.
- Incorrect handshake length.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/3136de53b1996f15.
Report an issue: GitHub.