{"record":{"id":"2cb9853c1d770ac5","repo":"gchq/CyberChef","slug":"data-is-not-a-valid-tls-client-hello-quic-is-not","errorCode":null,"errorMessage":"Data is not a valid TLS Client Hello. QUIC is not yet supported.\n${err}","messagePattern":"Data is not a valid TLS Client Hello\\. QUIC is not yet supported\\.\n(.+?)","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/JA4.mjs","lineNumber":32,"sourceCode":"import { toHexFast } from \"./Hex.mjs\";\nimport { runHash } from \"./Hash.mjs\";\nimport Utils from \"../Utils.mjs\";\n\n\n/**\n * Calculate the JA4 from a given TLS Client Hello Stream\n * @param {Uint8Array} bytes\n * @returns {string}\n */\nexport function toJA4(bytes) {\n    let tlsr = {};\n    try {\n        tlsr = parseTLSRecord(bytes);\n        if (tlsr.handshake.value.handshakeType.value !== 0x01) {\n            throw new Error();\n        }\n    } catch (err) {\n        throw new OperationError(\"Data is not a valid TLS Client Hello. QUIC is not yet supported.\\n\" + err);\n    }\n\n    /* QUIC\n        “q” or “t”, which denotes whether the hello packet is for QUIC or TCP.\n        TODO: Implement QUIC\n    */\n    const ptype = \"t\";\n\n    /* TLS Version\n        TLS version is shown in 3 different places. If extension 0x002b exists (supported_versions), then the version\n        is the highest value in the extension. Remember to ignore GREASE values. If the extension doesn’t exist, then\n        the TLS version is the value of the Protocol Version. Handshake version (located at the top of the packet)\n        should be ignored.\n    */\n    let version = tlsr.handshake.value.helloVersion.value;\n    for (const ext of tlsr.handshake.value.extensions.value) {\n        if (ext.type.value === \"supported_versions\") {\n            version = parseHighestSupportedVersion(ext.value.data);","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/JA4.mjs#L14-L50","documentation":"Thrown by toJA4 when the input cannot be parsed as a TLS Client Hello. The function wraps parseTLSRecord in a try/catch and additionally requires handshakeType === 0x01 (ClientHello); any parse failure (truncated record, non-TLS data, wrong handshake type) or a non-ClientHello record is re-thrown as an OperationError with the original error appended. QUIC Initial packets are explicitly not supported.","triggerScenarios":"Passing a TLS Server Hello (type 0x02), a Certificate/Alert/ApplicationData record, a QUIC Initial packet, a truncated/partial capture, an encrypted record, or non-TLS bytes (e.g. HTTP).","commonSituations":"Selecting the wrong packet from a PCAP; feeding a reassembled-but-wrong-direction record; QUIC traffic; missing TCP reassembly so the record is incomplete; encrypted data mistaken for a handshake.","solutions":["Confirm the bytes are a Client Hello (handshake type 0x01) and a complete TLS record.","Use toJA4S for Server Hello inputs.","Reassemble the TCP stream before extracting the record.","Filter out QUIC traffic (use a QUIC-aware tool instead)."],"exampleFix":"// before\ntoJA4(serverHelloBytes); // wrong direction\n\n// after\ntoJA4S(serverHelloBytes);","handlingStrategy":"try-catch","validationCode":"// Cheap TLS Client Hello sanity check (record + handshake + type 0x01).\nfunction looksLikeClientHello(bytes) {\n  return bytes.length >= 11 &&\n    bytes[0] === 0x16 &&               // ContentType: Handshake\n    bytes[1] === 0x03 &&               // Protocol version TLS (3.x)\n    bytes[5] === 0x01 &&               // HandshakeType: ClientHello\n    Number.isInteger(bytes[6]);\n}\nif (!looksLikeClientHello(bytes)) throw new Error(\"Not a TLS Client Hello record\");\ntoJA4(bytes);","typeGuard":"const isLikelyClientHello = bytes =>\n  bytes.length >= 11 && bytes[0] === 0x16 && bytes[5] === 0x01;","tryCatchPattern":"try {\n  toJA4(bytes);\n} catch (err) {\n  if (err instanceof OperationError && /not a valid TLS Client Hello/.test(err.message)) {\n    // wrong packet direction, truncated, QUIC, or non-TLS; re-select input\n  } else throw err;\n}","preventionTips":["Select the Client Hello (handshake type 0x01) from the capture, not the Server Hello.","Reassemble the TCP stream so the TLS record is complete.","Filter out QUIC; it is explicitly unsupported."],"tags":["tls","ja4","networking","fingerprinting","quic"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}