gchq/CyberChef · error · OperationError

Rotor wiring must be 26 unique uppercase letters

Error message

Rotor wiring must be 26 unique uppercase letters

What it means

Thrown by the Rotor constructor when the wiring argument fails /^[A-Z]{26}$/ — i.e. it is not exactly 26 uppercase ASCII letters. This is the first format gate before uniqueness is checked; length, case, and character class are all enforced here.

Source

Thrown at src/core/lib/Enigma.mjs:94

    }
    throw new OperationError("i2a called on value outside 0..25");
}

/**
 * A rotor in the Enigma machine.
 */
export class Rotor {
    /**
     * Rotor constructor.
     *
     * @param {string} wiring - A 26 character string of the wiring order.
     * @param {string} steps - A 0..26 character string of stepping points.
     * @param {char} ringSetting - The ring setting.
     * @param {char} initialPosition - The initial position of the rotor.
     */
    constructor(wiring, steps, ringSetting, initialPosition) {
        if (!/^[A-Z]{26}$/.test(wiring)) {
            throw new OperationError("Rotor wiring must be 26 unique uppercase letters");
        }
        if (!/^[A-Z]{0,26}$/.test(steps)) {
            throw new OperationError("Rotor steps must be 0-26 unique uppercase letters");
        }
        if (!/^[A-Z]$/.test(ringSetting)) {
            throw new OperationError("Rotor ring setting must be exactly one uppercase letter");
        }
        if (!/^[A-Z]$/.test(initialPosition)) {
            throw new OperationError("Rotor initial position must be exactly one uppercase letter");
        }
        this.map = new Array(26);
        this.revMap = new Array(26);
        const uniq = {};
        for (let i=0; i<LETTERS.length; i++) {
            const a = a2i(LETTERS[i]);
            const b = a2i(wiring[i]);
            this.map[a] = b;
            this.revMap[b] = a;

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Pass only the 26-letter wiring portion; strip anything from '<' onward (e.g. value.split('<')[0]).
  2. Ensure wiring is exactly 26 uppercase A-Z characters.
  3. Validate against /^[A-Z]{26}$/ before constructing the Rotor.

Example fix

// before
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCJ<R', 'R', 'A', 'A'); // 28 chars incl '<R'

// after
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCJ', 'R', 'A', 'A');
Defensive patterns

Strategy: validation

Validate before calling

function normaliseRotorValue(value) {
  // ROTORS entries look like 'EKMFLGDQVZNTOWYHXUSPAIBRCJ<R'
  return value.split("<")[0];
}
const wiring = normaliseRotorValue(rotorValue);
if (!/^[A-Z]{26}$/.test(wiring)) {
  throw new Error("Rotor wiring must be exactly 26 uppercase letters.");
}
new Rotor(wiring, steps, ringSetting, initialPosition);

Type guard

function isRotorWiringFormat(s) {
  return typeof s === "string" && /^[A-Z]{26}$/.test(s);
}

Prevention

When it happens

Trigger: new Rotor(wiring, ...) where wiring is fewer/more than 26 chars, contains lowercase letters, digits, the stepping marker '<', whitespace, or non-ASCII. Commonly happens when passing a full ROTORS value string like 'EKMFLGDQVZNTOWYHXUSPAIBRCJ<R' as wiring without stripping the '<R' suffix.

Common situations: Passing the raw 'value' field from the ROTORS table (which appends '<' and step letters) directly as wiring; truncated/copied wiring strings; lowercase input; off-by-one length from a manual transcription.

Related errors


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