{"record":{"id":"5ca497ceb52f89ff","repo":"gchq/CyberChef","slug":"invalid-hexadecimal-input-length-must-be-even","errorCode":null,"errorMessage":"Invalid hexadecimal input. Length must be even.","messagePattern":"Invalid hexadecimal input\\. Length must be even\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/DisassembleARM.mjs","lineNumber":91,"sourceCode":"            startAddress,\n            showHex,\n            showPosition\n        ] = args;\n\n        // Remove whitespace from input\n        const hexInput = input.replace(/\\s/g, \"\");\n\n        // Validate hex input\n        if (!/^[0-9a-fA-F]*$/.test(hexInput)) {\n            throw new OperationError(\"Invalid hexadecimal input. Please provide valid hex characters only.\");\n        }\n\n        if (hexInput.length === 0) {\n            return \"\";\n        }\n\n        if (hexInput.length % 2 !== 0) {\n            throw new OperationError(\"Invalid hexadecimal input. Length must be even.\");\n        }\n\n        // Convert hex string to byte array\n        const bytes = [];\n        for (let i = 0; i < hexInput.length; i += 2) {\n            bytes.push(parseInt(hexInput.substr(i, 2), 16));\n        }\n\n        // Determine architecture constant\n        let arch;\n        if (architecture === \"ARM64 (AArch64)\") {\n            arch = cs.ARCH_ARM64;\n        } else {\n            arch = cs.ARCH_ARM;\n        }\n\n        // Determine mode constant\n        let modeValue = cs.MODE_LITTLE_ENDIAN;","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/DisassembleARM.mjs#L73-L109","documentation":"Thrown by Disassemble ARM run() when the hex string has an odd number of characters after whitespace removal. Each byte is two hex digits; an odd length means a half-byte is unpaired and cannot be parsed into a byte array. The check runs after the character-class check and after the empty-input early return.","triggerScenarios":"A hex string whose length % 2 != 0: a missing leading zero (e.g. '1A3' instead of '01A3' or '1A30'), a truncated copy-paste that drops one nibble, or a stray digit appended.","commonSituations":"Copy-paste truncation dropping the last nibble; dropping a leading '0' from the first byte; concatenating hex lines and losing a character at a join; OCR/typing error.","solutions":["Count the hex digits and pad/trim to an even length.","If a leading nibble is missing, prepend '0' to the first byte (e.g. '1A3' -> '01A3').","If the last nibble is spurious, drop it; if it is real, add its missing partner.","Re-dump the bytes with a tool that emits two digits per byte."],"exampleFix":"// before\ninput: \"90 00 00 1\"  // last byte missing a nibble -> odd length\n\n// after\ninput: \"90 00 00 14\" // even length","handlingStrategy":"validation","validationCode":"function isEvenLengthHex(s) {\n    const h = String(s).replace(/\\s/g, \"\");\n    return /^[0-9a-fA-F]*$/.test(h) && h.length % 2 === 0;\n}","typeGuard":"/** @returns {boolean} */\nfunction isEvenLengthHexString(s) {\n    const h = typeof s === \"string\" ? s.replace(/\\s/g, \"\") : \"\";\n    return /^[0-9a-fA-F]*$/.test(h) && h.length % 2 === 0;\n}","tryCatchPattern":"try {\n    out = disassembleArm.run(input, args);\n} catch (e) {\n    if (e instanceof OperationError && /Length must be even/.test(e.message)) {\n        // pad leading 0 or trim a stray trailing nibble\n    } else throw e;\n}","preventionTips":["Ensure an even number of hex digits (two per byte).","Prepend '0' if the first byte lost its leading nibble.","Re-dump bytes with a tool that always emits two digits per byte.","Re-count after copy-paste to catch truncated nibbles."],"tags":["disassembly","arm","hex","validation"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}