{"record":{"id":"a1ddaddae7fde846","repo":"gchq/CyberChef","slug":"rotor-i-must-be-provided","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/Enigma.mjs","lineNumber":141,"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 model = args[0];\n        const reflectorstr = args[13];\n        const plugboardstr = args[14];\n        const removeOther = args[15];\n        const rotors = [];","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/Enigma.mjs#L123-L159","documentation":"Thrown in Enigma.parseRotorStr when a rotor specification string is ''. Rotors are editableOption fields combining 26-letter wiring (and optional '<' stepping points) into one string; parseRotorStr splits it. An empty value means no rotor wiring for that slot, which is fatal because the machine cannot step/encipher without a rotor. The index i is interpolated to identify which slot (left-hand/middle/right-hand/fourth) is empty.","triggerScenarios":"A rotor editableOption field was cleared so its value becomes '', a custom rotor string pasted as empty, or an imported recipe stored an empty rotor value. The Model argSelector toggles the 4th-rotor slot, so switching models with a stale empty value can expose it.","commonSituations":"Clearing a rotor field to type custom wiring and forgetting to fill it; loading a recipe saved with a blank rotor; switching between 3-rotor and 4-rotor models where the 4th slot was left empty.","solutions":["Provide a valid rotor wiring string - a permutation of A-Z, optionally followed by '<' and stepping letters, e.g. 'EKMFLGDQVZNTOWYHXUSPAIBRCJ<Q'.","Select a built-in rotor from the dropdown rather than clearing it.","For imported recipes, ensure no rotor slot is empty before running."],"exampleFix":"// before\nparseRotorStr('', 2);                       // empty slot -> throws\n// after\nparseRotorStr('EKMFLGDQVZNTOWYHXUSPAIBRCJ<Q', 2);","handlingStrategy":"validation","validationCode":"function parseRotor(rotor, i) {\n  if (typeof rotor !== \"string\" || rotor === \"\") throw new Error(`rotor ${i} must be provided`);\n  return rotor.includes(\"<\") ? rotor.split(\"<\", 2) : [rotor, \"\"];\n}\n// ensure every required rotor slot is non-empty before running Enigma\nfor (const [i, rot] of requiredRotors.entries()) parseRotor(rot, i);","typeGuard":"const isNonEmptyRotor = (s) => typeof s === \"string\" && s.length > 0;","tryCatchPattern":null,"preventionTips":["Never clear a rotor field; select a built-in rotor or type full 26-letter wiring.","Validate that all rotor slots (including the 4th for 4-rotor models) are non-empty before running.","Sanity-check imported recipes for blank rotor values."],"tags":["cipher","enigma","input-validation","argument-validation","operation-error"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}