gchq/CyberChef · error · OperationError

Invalid number of rounds

Error message

Invalid number of rounds: ${rounds}

Rounds must be an integer between 1 and 255. Standard XTEA uses 32 rounds.

What it means

Thrown by XTEADecrypt.run when args[6] (rounds) is not an integer or falls outside 1–255. Standard XTEA uses 32 rounds; the bounds let you vary it while staying in a single byte, but the count must match what was used for encryption or decryption yields garbage rather than an error.

Solutions

  1. Use the same rounds value that was used to encrypt (commonly 32).
  2. Ensure rounds is passed as a number, not a string, and is an integer within 1–255.
  3. If unsure of the original count, try 32 (the XTEA standard) first.

Example fix

// before
args:[key, iv, "CBC", "Hex", "Hex", "PKCS5", "33"]; // string -> not integer
// after
args:[key, iv, "CBC", "Hex", "Hex", "PKCS5", 32];
Defensive patterns

Strategy: validation

Validate before calling

function xteaRoundsArg(rounds) {
  if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255) throw new Error("rounds must be an integer 1..255");
  return rounds;
}

Type guard

const isValidXteaRounds = (r) => Number.isInteger(r) && r >= 1 && r <= 255;

Try / catch

try { chef.bake(data, recipe); } catch (e) { if (/Invalid number of rounds/.test(e.message)) { /* set rounds=32 */ } else throw e; }

Prevention

When it happens

Trigger: rounds is a fractional number, NaN, <1, >255, or supplied as a JSON string (fails Number.isInteger). Note: a wrong-but-valid integer (e.g. 33 instead of 32) does NOT throw — it silently decrypts incorrectly.

Common situations: Mismatched round counts between encrypt and decrypt operations; recipe config serialised with rounds as a string; manual override to a non-standard count.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/baa3952c9baaac7e. Report an issue: GitHub.

Appendix: source

Thrown at src/core/operations/XTEADecrypt.mjs:96

    run(input, args) {
        const key = Utils.convertToByteArray(args[0].string, args[0].option),
            iv = Utils.convertToByteArray(args[1].string, args[1].option),
            [,, mode, inputType, outputType, padding, rounds] = args;

        if (key.length !== 16)
            throw new OperationError(`Invalid key length: ${key.length} bytes

XTEA requires a key length of 16 bytes (128 bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);

        if (iv.length !== TEA_BLOCK_SIZE && iv.length !== 0 && mode !== "ECB")
            throw new OperationError(`Invalid IV length: ${iv.length} bytes

XTEA uses an IV length of ${TEA_BLOCK_SIZE} bytes (${TEA_BLOCK_SIZE * 8} bits).
Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);

        if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
            throw new OperationError(`Invalid number of rounds: ${rounds}

Rounds must be an integer between 1 and 255. Standard XTEA uses 32 rounds.`);

        // Default IV to null bytes if empty (like AES)
        const actualIv = iv.length === 0 ? new Array(TEA_BLOCK_SIZE).fill(0) : iv;

        input = Utils.convertToByteArray(input, inputType);
        const output = decryptXTEA(input, key, actualIv, mode, padding, rounds);
        return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
    }

}

export default XTEADecrypt;

View on GitHub (pinned to 4290ea7539)