gchq/CyberChef · error · OperationError
M61 custom lugs must be 61 long and can only include . or x
Error message
M61 custom lugs must be 61 long and can only include . or x
What it means
Thrown by the Lorenz operation only when 'Wheel Pattern' is 'Custom'. The Μ61 motor wheel has 61 cams, so its lug pattern must be exactly 61 characters matching ^[.xX]*$. Guard is on line 288 of src/core/operations/Lorenz.mjs.
Source
Thrown at src/core/operations/Lorenz.mjs:288
if (m37<1 || m37>37) throw new OperationError("Μ37 start must be between 1 and 37");
if (m61<1 || m61>61) throw new OperationError("Μ61 start must be between 1 and 61");
if (x1<1 || x1>41) throw new OperationError("Χ1 start must be between 1 and 41");
if (x2<1 || x2>31) throw new OperationError("Χ2 start must be between 1 and 31");
if (x3<1 || x3>29) throw new OperationError("Χ3 start must be between 1 and 29");
if (x4<1 || x4>26) throw new OperationError("Χ4 start must be between 1 and 26");
if (x5<1 || x5>23) throw new OperationError("Χ5 start must be between 1 and 23");
// Initialise chosen wheel pattern
let chosenSetting = "";
if (pattern === "Custom") {
const re = new RegExp("^[.xX]*$");
if (lugs1.length !== 43 || !re.test(lugs1)) throw new OperationError("Ψ1 custom lugs must be 43 long and can only include . or x ");
if (lugs2.length !== 47 || !re.test(lugs2)) throw new OperationError("Ψ2 custom lugs must be 47 long and can only include . or x");
if (lugs3.length !== 51 || !re.test(lugs3)) throw new OperationError("Ψ3 custom lugs must be 51 long and can only include . or x");
if (lugs4.length !== 53 || !re.test(lugs4)) throw new OperationError("Ψ4 custom lugs must be 53 long and can only include . or x");
if (lugs5.length !== 59 || !re.test(lugs5)) throw new OperationError("Ψ5 custom lugs must be 59 long and can only include . or x");
if (lugm37.length !== 37 || !re.test(lugm37)) throw new OperationError("M37 custom lugs must be 37 long and can only include . or x");
if (lugm61.length !== 61 || !re.test(lugm61)) throw new OperationError("M61 custom lugs must be 61 long and can only include . or x");
if (lugx1.length !== 41 || !re.test(lugx1)) throw new OperationError("Χ1 custom lugs must be 41 long and can only include . or x");
if (lugx2.length !== 31 || !re.test(lugx2)) throw new OperationError("Χ2 custom lugs must be 31 long and can only include . or x");
if (lugx3.length !== 29 || !re.test(lugx3)) throw new OperationError("Χ3 custom lugs must be 29 long and can only include . or x");
if (lugx4.length !== 26 || !re.test(lugx4)) throw new OperationError("Χ4 custom lugs must be 26 long and can only include . or x");
if (lugx5.length !== 23 || !re.test(lugx5)) throw new OperationError("Χ5 custom lugs must be 23 long and can only include . or x");
chosenSetting = INIT_PATTERNS["No Pattern"];
chosenSetting.S[1] = this.readLugs(lugs1);
chosenSetting.S[2] = this.readLugs(lugs2);
chosenSetting.S[3] = this.readLugs(lugs3);
chosenSetting.S[4] = this.readLugs(lugs4);
chosenSetting.S[5] = this.readLugs(lugs5);
chosenSetting.M[1] = this.readLugs(lugm61);
chosenSetting.M[2] = this.readLugs(lugm37);
chosenSetting.X[1] = this.readLugs(lugx1);
chosenSetting.X[2] = this.readLugs(lugx2);
chosenSetting.X[3] = this.readLugs(lugx3);
chosenSetting.X[4] = this.readLugs(lugx4);
chosenSetting.X[5] = this.readLugs(lugx5);View on GitHub (pinned to 4290ea7539)
Solutions
- Provide a Μ61 lugs string of exactly 61 characters using only '.', 'x', 'X'.
- Edit a known-good 61-character pattern in place rather than retyping.
- Pre-validate with /^[.xX]{61}$/ before running.
Example fix
// before: args[25] = ".xxxx" (5 chars) -> throws // after: args[25] = ".xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx..." (61 chars) -> ok
Defensive patterns
Strategy: validation
Validate before calling
// Μ61 lugs (args[25]) must match /^[.xX]{61}$/ when pattern === 'Custom'.
function validateCustomLugs(str, size, name) {
if (typeof str !== "string" || !new RegExp(`^[.xX]{${size}}$`).test(str)) {
throw new Error(`${name} lugs must be exactly ${size} chars of '.', 'x', or 'X'`);
}
}
if (args[1] === "Custom") validateCustomLugs(args[25], 61, "M61"); Type guard
const isMu61Lugs = (s) => typeof s === "string" && /^[.xX]{61}$/.test(s); Try / catch
try {
lorenz.run(input, args);
} catch (err) {
if (err instanceof OperationError && /M61 custom lugs/.test(err.message)) {
args[25] = ".xxxx.xxxx.xxx.xxxx.xx....xxx.xxxx.xxxx.xxxx.xxxx.xxx.xxxx..."; // known-good 61-char pattern
} else throw err;
} Prevention
- Μ61 lug strings must be exactly 61 characters — watch for off-by-one (60) truncation.
- Do not confuse with Μ37's 37-char field.
- Validate with /^[.xX]{61}$/ before running; strip any trailing newline first.
When it happens
Trigger: Calling Lorenz.run() with pattern='Custom' where args[25] (Μ61 lugs) is not exactly 61 characters or contains characters other than '.', 'x', 'X'.
Common situations: Custom pattern with a Μ61 string truncated (e.g. to 60 chars); a value copied from Μ37 (37 chars); an invalid character introduced during editing; trailing newline counted as a character.
Related errors
- M37 custom lugs must be 37 long and can only include . or x
- Ψ1 custom lugs must be 43 long and can only include . or x
- Ψ2 custom lugs must be 47 long and can only include . or x
- Ψ3 custom lugs must be 51 long and can only include . or x
- Ψ4 custom lugs must be 53 long and can only include . or x
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/e97ea8c1c9e4c78b.
Report an issue: GitHub.