{"record":{"id":"b17e5cbc7ffd5068","repo":"gchq/CyberChef","slug":"rotor-i-must-be-provided-b17e5c","errorCode":null,"errorMessage":"Rotor ${i} must be provided.","messagePattern":"Rotor (.+?) must be provided\\.","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/Typex.mjs","lineNumber":173,"sourceCode":"                name: \"Strict output\",\n                hint: \"Remove non-alphabet letters and group output\",\n                type: \"boolean\",\n                value: true\n            },\n        ];\n    }\n\n    /**\n     * Helper - for ease of use rotors are specified as a single string; this\n     * method breaks the spec string into wiring and steps parts.\n     *\n     * @param {string} rotor - Rotor specification string.\n     * @param {number} i - For error messages, the number of this rotor.\n     * @returns {string[]}\n     */\n    parseRotorStr(rotor, i) {\n        if (rotor === \"\") {\n            throw new OperationError(`Rotor ${i} must be provided.`);\n        }\n        if (!rotor.includes(\"<\")) {\n            return [rotor, \"\"];\n        }\n        return rotor.split(\"<\", 2);\n    }\n\n    /**\n     * @param {string} input\n     * @param {Object[]} args\n     * @returns {string}\n     */\n    run(input, args) {\n        const reflectorstr = args[20];\n        const plugboardstr = args[21];\n        const typexKeyboard = args[22];\n        const removeOther = args[23];\n        const rotors = [];","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/Typex.mjs#L155-L191","documentation":"Thrown by the Typex operation's parseRotorStr helper when one of the five rotor specification strings (args[0], args[4], args[8], args[12], args[16]) is the empty string. Each rotor arg is an editableOption whose value is a wiring spec optionally followed by '<' and stepping points; an empty value cannot define a rotor.","triggerScenarios":"Clearing/customising a rotor editableOption to an empty string, or loading a recipe/saved state where a rotor field was blanked. The i in the message is the 1-based-ish rotor index from the loop in run().","commonSituations":"User deletes the rotor wiring text in the UI to start typing a custom rotor and runs before finishing, or imports a recipe whose rotor fields did not survive serialisation.","solutions":["Restore a non-empty rotor value: select one of the built-in ROTORS from the dropdown.","If defining a custom rotor, enter the 26-letter wiring string (optionally '<' + steps).","Check saved recipe JSON for empty rotor fields and repopulate them."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for (let i = 0; i < 5; i++) {\n  const rotor = args[i * 4];\n  if (!rotor || rotor === \"\") {\n    throw new Error(`Rotor ${i} must not be empty`);\n  }\n}","typeGuard":"function rotorsAreProvided(args) { return [0,4,8,12,16].every(i => typeof args[i] === \"string\" && args[i] !== \"\"); }","tryCatchPattern":null,"preventionTips":["Always leave a built-in rotor selected when customising.","Validate imported Typex recipes for blank rotor fields."],"tags":["typex","validation","argument-error","recipe"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}