gchq/CyberChef · error · OperationError

err.message.replace("Rotor", "Plugboard")

Error message

err.message.replace("Rotor", "Plugboard")

What it means

Thrown by the Typex Plugboard constructor in Typex.mjs in the catch block: when the mirrored wiring passes the regex but the Enigma Rotor superclass rejects it (typically because the 26 letters are not a unique permutation), the constructor rewrites the superclass error message, replacing the substring "Rotor" with "Plugboard" and re-throws as an OperationError. So the literal thrown text is dynamic — it is whatever the rotor error said, with 'Rotor' swapped for 'Plugboard' (e.g. 'Plugboard wiring must be 26 unique letters').

Source

Thrown at src/core/lib/Typex.mjs:204

        // Typex input wiring is backwards vs Enigma: that is, letters enter the rotors in a
        // clockwise order, vs. Enigma's anticlockwise (or vice versa depending on which side
        // you're looking at it from). I'm doing the transform here to avoid having to rewrite
        // the Engima crypt() method in Typex as well.
        // Note that the wiring for the reflector is the same way around as Enigma, so no
        // transformation is necessary on that side.
        // We're going to achieve this by mapping the plugboard settings through an additional
        // transform that mirrors the alphabet before we pass it to the superclass.
        if (!/^[A-Z]{26}$/.test(wiring)) {
            throw new OperationError("Plugboard wiring must be 26 unique uppercase letters");
        }
        const reversed = "AZYXWVUTSRQPONMLKJIHGFEDCB";
        wiring = wiring.replace(/./g, x => {
            return reversed[Enigma.a2i(x)];
        });
        try {
            super(wiring, "", "A", "A");
        } catch (err) {
            throw new OperationError(err.message.replace("Rotor", "Plugboard"));
        }
    }

    /**
     * Transform a character through this rotor forwards.
     *
     * @param {number} c - The character.
     * @returns {number}
     */
    transform(c) {
        return Utils.mod(this.map[Utils.mod(c + this.pos, 26)] - this.pos, 26);
    }

    /**
     * Transform a character through this rotor backwards.
     *
     * @param {number} c - The character.
     * @returns {number}

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Ensure the wiring is a true permutation: every letter A-Z appears exactly once. Check with new Set(wiring).size === 26.
  2. If you want a pass-through plugboard, use the identity "ABCDEFGHIJKLMNOPQRSTUVWXYZ".
  3. Generate wirings with a verified shuffle of the alphabet rather than ad-hoc string building.

Example fix

// before: 'A' repeated, 'Z' missing
new Plugboard("ABCDEFGHIJKLMNOPQRSTUVAWXYZ"); // superclass throws, rewritten
// after: true permutation
new Plugboard("AYZXWVUTSRQPONMLKJIHGFEDCB");
Defensive patterns

Strategy: validation

Validate before calling

function isAlphabetPermutation(w) {
    if (typeof w !== "string" || w.length !== 26) return false;
    const seen = new Set();
    for (const ch of w) {
        if (ch < "A" || ch > "Z") return false;
        if (seen.has(ch)) return false;
        seen.add(ch);
    }
    return seen.size === 26;
}
if (!isAlphabetPermutation(wiring)) {
    throw new Error(
        `Plugboard wiring must be a permutation of A-Z (each letter exactly once). Got: '${wiring}'.`
    );
}
new Typex.Plugboard(wiring);

Type guard

function isAlphabetPermutation(w) {
    if (typeof w !== "string" || w.length !== 26) return false;
    const seen = new Set();
    for (const ch of w) {
        if (ch < "A" || ch > "Z") return false;
        if (seen.has(ch)) return false;
        seen.add(ch);
    }
    return seen.size === 26;
}

Try / catch

try {
    plugboard = new Typex.Plugboard(wiring);
} catch (e) {
    if (e instanceof OperationError && /Plugboard/i.test(e.message)) {
        // message is the rewritten rotor error; surface a clearer one
        return { error: `Plugboard wiring must be a permutation of A-Z (no repeats).` };
    }
    throw e;
}

Prevention

When it happens

Trigger: Constructing `new Typex.Plugboard(wiring)` with a 26-uppercase-letter string that is NOT a permutation of A-Z — i.e. it has duplicate letters and is missing others. The regex at line 194 passes (right length and charset) but the superclass uniqueness check fails, and this catch fires.

Common situations: Hand-typed wiring with a repeated letter (e.g. two 'A's); wiring generated by a buggy permutation routine that can repeat; copy-paste that duplicated a letter; an intentional non-bijective map that Typex (via Enigma) does not allow.

Related errors


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