{"record":{"id":"bd930c5a139fedf6","repo":"gchq/CyberChef","slug":"not-handshake-data","errorCode":null,"errorMessage":"Not handshake data.","messagePattern":"Not handshake data\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/TLS.mjs","lineNumber":30,"sourceCode":"/**\n * Parse a TLS Record\n * @param {Uint8Array} bytes\n * @returns {JSON}\n */\nexport function parseTLSRecord(bytes) {\n    const s = new Stream(bytes);\n    const b = s.clone();\n    const r = {};\n\n    // Content type\n    r.contentType = {\n        description: \"Content Type\",\n        length: 1,\n        data: b.getBytes(1),\n        value: s.readInt(1)\n    };\n    if (r.contentType.value !== 0x16)\n        throw new OperationError(\"Not handshake data.\");\n\n    // Version\n    r.version = {\n        description: \"Protocol Version\",\n        length: 2,\n        data: b.getBytes(2),\n        value: s.readInt(2)\n    };\n\n    // Length\n    r.length = {\n        description: \"Record Length\",\n        length: 2,\n        data: b.getBytes(2),\n        value: s.readInt(2)\n    };\n    if (s.length !== r.length.value + 5)\n        throw new OperationError(\"Incorrect handshake length.\");","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/TLS.mjs#L12-L48","documentation":"Thrown by parseTLSRecord() in TLS.mjs when the first byte of the record (the TLS content type) is not 0x16. Value 0x16 designates a Handshake record; this parser only decodes handshake records. Any other content type (0x14 ChangeCipherSpec, 0x15 Alert, 0x17 ApplicationData, 0x16 itself absent) or non-TLS data is rejected up front before further parsing.","triggerScenarios":"Calling parseTLSRecord() with bytes that are not a TLS handshake record: an ApplicationData record (0x17), an Alert (0x15), a full capture where the handshake is buried mid-stream, raw application traffic, or unrelated binary data. Also when the byte order is reversed or a TLS 1.3 encrypted ClientHello is fed in after encryption.","commonSituations":"Parsing a packet capture from the wrong record offset; feeding the entire TCP stream rather than the first record; trying to parse a ServerHello fragment that arrived alone after the ClientHello; using the parser on DTLS or QUIC framing which differ.","solutions":["Confirm the input is the bytes of a single TLS handshake record whose first byte equals 0x16.","If parsing a stream, locate each record by reading the 5-byte TLS record header (type, version, length) and only pass handshake (0x16) records to this function.","If you actually need to parse Alert/ApplicationData, this parser does not support those — use a full TLS dissector."],"exampleFix":"// before\nparseTLSRecord(appDataRecordBytes); // first byte 0x17\n// after: extract the handshake record first\nconst rec = findRecordByType(stream, 0x16);\nparseTLSRecord(rec);","handlingStrategy":"validation","validationCode":"function isHandshakeRecord(bytes) {\n    return bytes instanceof Uint8Array && bytes.length >= 1 && bytes[0] === 0x16;\n}\nif (!isHandshakeRecord(bytes)) {\n    throw new Error(\n        `Input is not a TLS handshake record (content type byte = 0x${(bytes[0] ?? 0).toString(16)}). ` +\n        `parseTLSRecord only decodes handshake (0x16) records.`\n    );\n}\nconst r = parseTLSRecord(bytes);","typeGuard":"function isHandshakeRecord(bytes) {\n    return (bytes instanceof Uint8Array || Array.isArray(bytes)) &&\n        bytes.length >= 1 && bytes[0] === 0x16;\n}","tryCatchPattern":"try {\n    record = parseTLSRecord(bytes);\n} catch (e) {\n    if (e instanceof OperationError && /Not handshake data/.test(e.message)) {\n        // skip non-handshake records when walking a stream\n        continue;\n    }\n    throw e;\n}","preventionTips":["When walking a TLS byte stream, read the 5-byte record header and dispatch on content type; only feed 0x16 records to parseTLSRecord.","Do not pass arbitrary binary or application-data captures to this parser.","For DTLS/QUIC or TLS 1.3 encrypted frames, use a dissector that supports them."],"tags":["tls","parsing","handshake","protocol-validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}