gchq/CyberChef · error · OperationError

Rotor wiring must have each letter exactly once

Error message

Rotor wiring must have each letter exactly once

What it means

Thrown by the Rotor constructor after building the wiring map: although wiring passed the 26-uppercase-letters format check, the letter set is not a permutation of A-Z (some letters repeat, others are absent). The code collects unique output letters into an object and requires all 26 to appear exactly once, which is what makes the rotor a bijection.

Source

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

        }
        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;
            uniq[b] = true;
        }
        if (Object.keys(uniq).length !== LETTERS.length) {
            throw new OperationError("Rotor wiring must have each letter exactly once");
        }
        const rs = a2i(ringSetting);
        this.steps = new Set();
        for (const x of steps) {
            this.steps.add(Utils.mod(a2i(x) - rs, 26));
        }
        if (this.steps.size !== steps.length) {
            // This isn't strictly fatal, but it's probably a mistake
            throw new OperationError("Rotor steps must be unique");
        }
        this.pos = Utils.mod(a2i(initialPosition) - rs, 26);
    }

    /**
     * Step the rotor forward by one.
     */
    step() {
        this.pos = Utils.mod(this.pos + 1, 26);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Ensure wiring is a permutation of the full alphabet (each letter A-Z exactly once).
  2. Validate new Set(wiring).size === 26 && wiring.length === 26 before constructing.
  3. Use a known-good rotor definition from the ROTORS table.

Example fix

// before
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCE', 'R', 'A', 'A'); // duplicate E, no J

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

Strategy: validation

Validate before calling

function isPermutationOfAlphabet(wiring) {
  return typeof wiring === "string" && wiring.length === 26 && new Set(wiring).size === 26 && /^[A-Z]+$/.test(wiring);
}
if (!isPermutationOfAlphabet(wiring)) {
  throw new Error("Rotor wiring must be a permutation of A-Z.");
}

Type guard

function isRotorWiringPermutation(s) {
  return typeof s === "string" && s.length === 26 && new Set(s).size === 26 && /^[A-Z]+$/.test(s);
}

Prevention

When it happens

Trigger: new Rotor(wiring, ...) where wiring is 26 uppercase letters but contains a duplicate (e.g. 'EKMFLGDQVZNTOWYHXUSPAIBRCE' with two E's and no J). The format regex passes but the uniqueness count fails.

Common situations: Hand-transcribed wiring with a typo duplicating a letter; copy-paste corruption; deliberately scrambled wiring that isn't a true permutation.

Related errors


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