gchq/CyberChef · warning · OperationError
Rotor steps must be unique
Error message
Rotor steps must be unique
What it means
Thrown by the Rotor constructor when, after normalising step letters against the ring setting, the resulting Set of step positions is smaller than the input steps string length — i.e. two distinct step letters map to the same turnover position. The comment notes this isn't strictly fatal but is treated as a probable mistake.
Source
Thrown at src/core/lib/Enigma.mjs:125
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);
return this.pos;
}
/**
* Transform a character through this rotor forwards.
*
* @param {number} c - The character.
* @returns {number}
*/View on GitHub (pinned to 4290ea7539)
Solutions
- Remove duplicate letters from the steps string.
- Confirm steps has no repeated characters before constructing (new Set(steps).size === steps.length).
- Use step letters directly from the canonical ROTORS definitions.
Example fix
// before
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCJ', 'RR', 'A', 'A'); // duplicate R
// after
new Rotor('EKMFLGDQVZNTOWYHXUSPAIBRCJ', 'R', 'A', 'A'); Defensive patterns
Strategy: validation
Validate before calling
function hasUniqueStepLetters(steps) {
return typeof steps === "string" && new Set(steps).size === steps.length;
}
if (!hasUniqueStepLetters(steps)) {
throw new Error("Rotor steps contain duplicate letters.");
} Type guard
function hasUniqueChars(s) {
return typeof s === "string" && new Set(s).size === s.length;
} Prevention
- Remove duplicate letters from the steps string.
- Derive steps from canonical ROTORS entries.
- Validate Set size equals string length before constructing.
When it happens
Trigger: new Rotor(wiring, steps, ringSetting, ...) where two step letters differ but Utils.mod(a2i(x) - rs, 26) collide. Also fires trivially when steps contains a repeated letter (e.g. 'RR'), since steps.length counts chars but Set dedupes.
Common situations: Duplicate letters in the steps string; passing a steps value derived from a malformed ROTORS entry; accidentally concatenating two rotor step strings.
Related errors
- Rotor wiring must be 26 unique uppercase letters
- Rotor steps must be 0-26 unique uppercase letters
- Rotor ring setting must be exactly one uppercase letter
- Rotor initial position must be exactly one uppercase letter
- Rotor wiring must have each letter exactly once
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/ff869106d2550efa.
Report an issue: GitHub.