{"record":{"id":"3bc3abd6f92ed358","repo":"gchq/CyberChef","slug":"name-must-be-a-whitespace-separated-list-of-upp","errorCode":null,"errorMessage":"${name} must be a whitespace-separated list of uppercase letter pairs","messagePattern":"(.+?) must be a whitespace-separated list of uppercase letter pairs","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/lib/Enigma.mjs","lineNumber":180,"sourceCode":" */\nclass PairMapBase {\n    /**\n     * PairMapBase constructor.\n     *\n     * @param {string} pairs - A whitespace separated string of letter pairs to swap.\n     * @param {string} [name='PairMapBase'] - For errors, the name of this object.\n     */\n    constructor(pairs, name=\"PairMapBase\") {\n        // I've chosen to make whitespace significant here to make a) code and\n        // b) inputs easier to read\n        this.pairs = pairs;\n        this.map = {};\n        if (pairs === \"\") {\n            return;\n        }\n        pairs.split(/\\s+/).forEach(pair => {\n            if (!/^[A-Z]{2}$/.test(pair)) {\n                throw new OperationError(name + \" must be a whitespace-separated list of uppercase letter pairs\");\n            }\n            const a = a2i(pair[0]), b = a2i(pair[1]);\n            if (a === b) {\n                // self-stecker\n                return;\n            }\n            if (Object.prototype.hasOwnProperty.call(this.map, a)) {\n                throw new OperationError(`${name} connects ${pair[0]} more than once`);\n            }\n            if (Object.prototype.hasOwnProperty.call(this.map, b)) {\n                throw new OperationError(`${name} connects ${pair[1]} more than once`);\n            }\n            this.map[a] = b;\n            this.map[b] = a;\n        });\n    }\n\n    /**","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/lib/Enigma.mjs#L162-L198","documentation":"Thrown by the PairMapBase constructor (parent of Plugboard and Reflector) when, after splitting the pairs string on whitespace, any token does not match /^[A-Z]{2}$/ — i.e. it is not exactly two uppercase letters. An empty pairs string is allowed (no connections); otherwise every whitespace-separated token must be a two-letter uppercase pair.","triggerScenarios":"new Plugboard(pairs) or new Reflector(pairs) where pairs contains a single letter, a 3+ letter token, lowercase, digits, a symbol, or stray punctuation. Whitespace-splitting means any malformed token triggers it.","commonSituations":"Pasting a reflector/plugboard spec in the wrong format (e.g. concatenated 'AYBRCU' instead of space-separated 'AY BR CU'); lowercase input; trailing punctuation; a single dangling letter from a typo.","solutions":["Format pairs as whitespace-separated two-uppercase-letter tokens (e.g. 'AY BR CU DH').","Uppercase the input and strip non-letter characters first.","Validate every token with /^[A-Z]{2}$/ before constructing."],"exampleFix":"// before\nnew Plugboard('AYBRCUDH'); // no spaces -> one 8-char token\n\n// after\nnew Plugboard('AY BR CU DH');","handlingStrategy":"validation","validationCode":"function normalisePairs(pairs) {\n  return pairs.toUpperCase().trim().split(/\\s+/).filter(Boolean);\n}\nconst tokens = normalisePairs(pairs);\nif (tokens.some(t => !/^[A-Z]{2}$/.test(t))) {\n  throw new Error(\"All pairs must be two uppercase letters separated by whitespace.\");\n}","typeGuard":"function isPairList(pairs) {\n  if (pairs === \"\") return true;\n  return pairs.split(/\\s+/).every(t => /^[A-Z]{2}$/.test(t));\n}","tryCatchPattern":null,"preventionTips":["Format pairs as space-separated two-letter uppercase tokens.","Uppercase and trim input before constructing.","Validate each whitespace-split token matches /^[A-Z]{2}$/."],"tags":["enigma","cryptography","input-validation","plugboard","reflector"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}