gchq/CyberChef · error · OperationError

Rotor steps must be 0-26 unique uppercase letters

Error message

Rotor steps must be 0-26 unique uppercase letters

What it means

Thrown by the Rotor constructor when the steps argument fails /^[A-Z]{0,26}$/ — i.e. it must be 0 to 26 uppercase ASCII letters. steps lists the rotor positions at which the adjacent rotor advances (the turnover points).

Source

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

/**
 * 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;
            uniq[b] = true;
        }
        if (Object.keys(uniq).length !== LETTERS.length) {

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Pass only the step-letters portion from after '<' in the ROTORS value (e.g. value.split('<')[1] || '').
  2. Ensure steps is 0-26 uppercase A-Z characters.
  3. Validate against /^[A-Z]{0,26}$/ before constructing.

Example fix

// before
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCJ', '<R', 'A', 'A'); // '<' not allowed

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

Strategy: validation

Validate before calling

function rotorStepsFromValue(value) {
  // returns the part after '<', or '' if none
  const parts = value.split("<");
  return parts.length > 1 ? parts[1] : "";
}
const steps = rotorStepsFromValue(rotorValue);
if (!/^[A-Z]{0,26}$/.test(steps)) {
  throw new Error("Rotor steps must be 0-26 uppercase letters.");
}

Type guard

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

Prevention

When it happens

Trigger: new Rotor(..., steps, ...) where steps contains lowercase letters, digits, symbols, the '<' marker, whitespace, or more than 26 characters. An empty string is allowed (rotor that never triggers a turnover).

Common situations: Passing the full ROTORS value (including wiring) as the steps argument; extracting steps but leaving the '<' prefix; lowercase turnover letters; passing null/undefined.

Related errors


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