gchq/CyberChef · error · OperationError
Byte length must be a positive integer
Error message
Byte length must be a positive integer
What it means
fromModhex(data, delim, byteLen) converts a Modhex string (Yubico's cbdefghijklnrtuv alphabet) back to a byte array. byteLen controls the per-byte hex grouping handed to fromHex. The guard rejects byteLen values that are < 1 or non-integral before any parsing happens.
Source
Thrown at src/core/lib/Modhex.mjs:133
/**
* Convert a modhex string into a byte array.
*
* @param {string} data
* @param {string} [delim]
* @param {number} [byteLen=2]
* @returns {byteArray}
*
* @example
* // returns [10,20,30]
* fromModhex("cl bf bu");
*
* // returns [10,20,30]
* fromModhex("cl:bf:bu", "Colon");
*/
export function fromModhex(data, delim="Auto", byteLen=2) {
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
throw new OperationError("Byte length must be a positive integer");
// The `.replace(/\s/g, "")` an interesting workaround: Hex "multiline" tests aren't actually
// multiline. Tests for Modhex fixes that, thus exposing the issue.
data = data.toLowerCase().replace(/\s/g, "");
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^cbdefghijklnrtuv]/gi : Utils.regexRep(delim);
data = data.split(delimRegex);
} else {
data = [data];
}
let regularHexString = "";
for (let i = 0; i < data.length; i++) {
for (const letter of data[i].split("")) {
regularHexString += HEX_ALPHABET_MAP[MODHEX_ALPHABET_MAP.indexOf(letter)];
}
}View on GitHub (pinned to 4290ea7539)
Solutions
- Pass a positive integer for byteLen (typically 2): fromModhex(data, 'Auto', 2).
- Coerce and clamp the value: Math.max(1, Math.floor(byteLen)) before calling.
- Re-check argument order: signature is (data, delim, byteLen), not (data, byteLen, delim).
- Validate in your UI layer that the byte-length selector cannot return 0 or non-integers.
Example fix
// before
fromModhex('cl bf bu', 2); // 2 is treated as delim, byteLen defaults but...
fromModhex('clbf', 'Auto', 0); // byteLen=0 -> error
// after
fromModhex('cl bf bu', 'Auto', 2); // explicit positive integer
const safeByteLen = Math.max(1, Math.floor(Number(byteLen) || 2));
fromModhex(data, 'Auto', safeByteLen); Defensive patterns
Strategy: validation
Validate before calling
function safeByteLen(n) {
const i = Math.floor(Number(n));
return Number.isInteger(i) && i >= 1 ? i : 2;
}
fromModhex(data, 'Auto', safeByteLen(maybeByteLen)); Type guard
function isPositiveIntegerByteLen(x): x is number {
return typeof x === 'number' && Number.isInteger(x) && x >= 1;
} Try / catch
try {
return fromModhex(data, delim, byteLen);
} catch (e) {
if (e instanceof OperationError && /positive integer/.test(e.message)) {
return fromModhex(data, delim, 2); // fall back to default
}
throw e;
} Prevention
- Always pass an explicit positive integer for byteLen (typically 2).
- Mind the argument order: (data, delim, byteLen).
- Constrain UI inputs so the byte-length selector cannot return 0.
- Coerce with Math.max(1, Math.floor(...)) before calling.
When it happens
Trigger: Calling fromModhex(data, delim, 0), fromModhex(data, delim, -1), or fromModhex(data, delim, 1.5). Also triggered by accidentally passing a string or other non-integer that satisfies the math check incorrectly, or by leaving the second argument off and having delim shifted into byteLen.
Common situations: Wrong argument order (passing delim where byteLen goes); UI dropdown returning 0 when 'None' is selected; calculation that produces a fractional byteLen; default value misconfigured in a recipe import.
Related errors
- unexpected character encountered: "${character}"
- Invalid Base64 alphabet length (${alphabet.length}): ${alpha
- Wrong key size
- Letter ${letter} is not in the key
- Invalid encoding
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/a2f86a02451eb989.
Report an issue: GitHub.