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
- Pass only the step-letters portion from after '<' in the ROTORS value (e.g. value.split('<')[1] || '').
- Ensure steps is 0-26 uppercase A-Z characters.
- 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
- Derive steps from the part after '<' in a ROTORS value, never the whole string.
- Allow empty string for rotors with no turnover points.
- Validate the regex before constructing.
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
- Rotor wiring must be 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
- Rotor steps must be unique
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/51c0110536bbeb8b.
Report an issue: GitHub.