{"record":{"id":"6b4bfcf77a3e4cc2","repo":"gchq/CyberChef","slug":"byte-length-must-be-a-positive-integer-6b4bfc","errorCode":null,"errorMessage":"Byte length must be a positive integer","messagePattern":"Byte length must be a positive integer","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/Hex.mjs","lineNumber":105,"sourceCode":"\n/**\n * Convert a hex string into a byte array.\n *\n * @param {string} data\n * @param {string} [delim]\n * @param {number} [byteLen=2]\n * @returns {byteArray}\n *\n * @example\n * // returns [10,20,30]\n * fromHex(\"0a 14 1e\");\n *\n * // returns [10,20,30]\n * fromHex(\"0a:14:1e\", \"Colon\");\n */\nexport function fromHex(data, delim=\"Auto\", byteLen=2) {\n    if (byteLen < 1 || Math.round(byteLen) !== byteLen)\n        throw new OperationError(\"Byte length must be a positive integer\");\n\n    if (delim !== \"None\") {\n        const delimRegex = delim === \"Auto\" ? /[^a-f\\d]|0x/gi : Utils.regexRep(delim);\n        data = data.split(delimRegex);\n    } else {\n        data = [data];\n    }\n\n    const output = [];\n    for (let i = 0; i < data.length; i++) {\n        for (let j = 0; j < data[i].length; j += byteLen) {\n            output.push(parseInt(data[i].substr(j, byteLen), 16));\n        }\n    }\n    return output;\n}\n\n","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/Hex.mjs#L87-L123","documentation":"Thrown by fromHex when the byteLen argument fails the positivity/integer guard (`byteLen < 1 || Math.round(byteLen) !== byteLen`). byteLen controls how many hex digits are grouped into each output byte (default 2). Zero, negative, fractional, or NaN values are rejected. This is an OperationError, so recipe execution treats it as expected output.","triggerScenarios":"Calling `fromHex(data, delim, 0)`, `fromHex(data, delim, -1)`, `fromHex(data, delim, 2.5)`, or passing a value that coerces to NaN. Also triggered by a recipe/UI supplying an out-of-range 'Byte length' argument.","commonSituations":"Misconfigured recipe argument; passing undefined through arithmetic that yields NaN; user typing 0 or a decimal in the Byte length field.","solutions":["Pass a positive integer byteLen (the typical value is 2).","Validate byteLen is a positive integer before invoking fromHex.","Default the argument explicitly when sourcing it from untrusted UI input."],"exampleFix":"// before\nfromHex(hexStr, \"Space\", 0);\n\n// after\nfromHex(hexStr, \"Space\", 2);","handlingStrategy":"validation","validationCode":"function fromHexSafe(data, delim = \"Auto\", byteLen = 2) {\n  if (!Number.isInteger(byteLen) || byteLen < 1) {\n    throw new Error(\"byteLen must be a positive integer\");\n  }\n  return fromHex(data, delim, byteLen);\n}","typeGuard":"const isPositiveInt = n => Number.isInteger(n) && n >= 1;","tryCatchPattern":"try {\n  fromHex(data, delim, byteLen);\n} catch (err) {\n  if (err instanceof OperationError && /Byte length must be a positive integer/.test(err.message)) {\n    // fix the byteLen argument (default to 2) and retry\n  } else throw err;\n}","preventionTips":["Default byteLen explicitly when sourcing it from UI/untrusted input.","Validate with Number.isInteger before calling fromHex.","Remember the typical value is 2 (two hex digits per byte)."],"tags":["hex","validation","argument","parsing"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}