gchq/CyberChef · error · OperationError

Rotor ring setting must be exactly one uppercase letter

Error message

Rotor ring setting must be exactly one uppercase letter

What it means

Thrown by the Rotor constructor when ringSetting fails /^[A-Z]$/ — it must be exactly one uppercase ASCII letter. The ring setting offsets the wiring relative to the alphabet and is combined with the step positions.

Source

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

 */
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) {
            throw new OperationError("Rotor wiring must have each letter exactly once");
        }
        const rs = a2i(ringSetting);

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Convert numeric ring settings to a letter: String.fromCharCode(64 + n) for n in 1-26 (so 1 -> 'A').
  2. Pass exactly one uppercase letter.
  3. Validate /^[A-Z]$/.test(ringSetting) before constructing.

Example fix

// before
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCJ', 'R', 1, 'A'); // number, not letter

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

Strategy: validation

Validate before calling

function ringSettingToLetter(n) {
  if (!Number.isInteger(n) || n < 1 || n > 26) throw new Error("Ring setting must be 1-26.");
  return String.fromCharCode(64 + n);
}
const ringSetting = ringSettingToLetter(numericRing);
if (!/^[A-Z]$/.test(ringSetting)) {
  throw new Error("Ring setting must be one uppercase letter.");
}

Type guard

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

Prevention

When it happens

Trigger: new Rotor(..., ringSetting, ...) where ringSetting is an empty string, more than one character, lowercase, a number, or a multi-char string like 'AA'.

Common situations: Passing a numeric ring setting (common in Enigma literature where ring settings are 1-26) instead of the letter A-Z; passing an empty value; case mismatch.

Related errors


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