{"record":{"id":"0c87bdd2968c1d2a","repo":"gchq/CyberChef","slug":"not-a-client-hello","errorCode":null,"errorMessage":"Not a Client Hello.","messagePattern":"Not a Client Hello\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/JA3Fingerprint.mjs","lineNumber":77,"sourceCode":"        input = Utils.convertToByteArray(input, inputFormat);\n        const s = new Stream(new Uint8Array(input));\n\n        const handshake = s.readInt(1);\n        if (handshake !== 0x16)\n            throw new OperationError(\"Not handshake data.\");\n\n        // Version\n        s.moveForwardsBy(2);\n\n        // Length\n        const length = s.readInt(2);\n        if (s.length !== length + 5)\n            throw new OperationError(\"Incorrect handshake length.\");\n\n        // Handshake type\n        const handshakeType = s.readInt(1);\n        if (handshakeType !== 1)\n            throw new OperationError(\"Not a Client Hello.\");\n\n        // Handshake length\n        const handshakeLength = s.readInt(3);\n        if (s.length !== handshakeLength + 9)\n            throw new OperationError(\"Not enough data in Client Hello.\");\n\n        // Hello version\n        const helloVersion = s.readInt(2);\n\n        // Random\n        s.moveForwardsBy(32);\n\n        // Session ID\n        const sessionIDLength = s.readInt(1);\n        s.moveForwardsBy(sessionIDLength);\n\n        // Cipher suites\n        const cipherSuitesLength = s.readInt(2);","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/JA3Fingerprint.mjs#L59-L95","documentation":"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.","triggerScenarios":"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).","commonSituations":"Using JA3 (client) on a server capture instead of JA3S; off-by-one slicing; inputFormat mismatch; feeding a Certificate/ServerHello record.","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."],"exampleFix":"// before\nja3.run(serverHelloRecord, ['Hex','Base64']); // type byte 2 -> Not a Client Hello.\n// after\nja3s.run(serverHelloRecord, ['Hex','Base64']); // use the Server Hello op","handlingStrategy":"validation","validationCode":"import Utils from \"src/core/Utils.mjs\";\nfunction assertClientHello(input, inputFormat) {\n  const b = Utils.convertToByteArray(input, inputFormat);\n  if (b.length < 6) throw new Error('record too short');\n  if (b[5] !== 1) {\n    throw new Error(`Handshake type ${b[5]} is not ClientHello (1). For ServerHello use JA3S.`);\n  }\n  return b;\n}","typeGuard":"function isClientHello(bytes) {\n  return bytes.length >= 6 && bytes[0] === 0x16 && bytes[5] === 1;\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["tls","network","parsing","cyberchef","input-validation","ja3"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}