{"record":{"id":"38900a35e5e61587","repo":"gchq/CyberChef","slug":"character-not-in-alphabet-c","errorCode":null,"errorMessage":"Character not in alphabet: '${c}'","messagePattern":"Character not in alphabet: '(.+?)'","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/FromBase45.mjs","lineNumber":71,"sourceCode":"        if (!input) return [];\n        const alphabet = Utils.expandAlphRange(args[0]).join(\"\");\n        const removeNonAlphChars = args[1];\n\n        const res = [];\n\n        // Remove non-alphabet characters\n        if (removeNonAlphChars) {\n            const re = new RegExp(\"[^\" + alphabet.replace(/[[\\]\\\\\\-^$]/g, \"\\\\$&\") + \"]\", \"g\");\n            input = input.replace(re, \"\");\n        }\n\n        for (const triple of Utils.chunked(input, 3)) {\n            triple.reverse();\n            let b = 0;\n            for (const c of triple) {\n                const idx = alphabet.indexOf(c);\n                if (idx === -1) {\n                    throw new OperationError(`Character not in alphabet: '${c}'`);\n                }\n                b *= 45;\n                b += idx;\n            }\n\n            if (b > 65535) {\n                throw new OperationError(`Triplet too large: '${triple.join(\"\")}'`);\n            }\n\n            if (triple.length > 2) {\n                /**\n                 * The last triple may only have 2 bytes so we push the MSB when we got 3 bytes\n                 * Pushing MSB\n                 */\n                res.push(b >> 8);\n            }\n\n            /**","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/FromBase45.mjs#L53-L89","documentation":"Thrown by From Base45 when a character in the (possibly filtered) input is not found in the 45-character alphabet (alphabet.indexOf(c) === -1). This only fires when 'Remove non-alphabet chars' is disabled, because otherwise such characters are stripped first. The offending character is shown in the message.","triggerScenarios":"Disabling 'Remove non-alphabet chars' and feeding input containing characters outside the Base45 alphabet [0-9A-Z space$%*+-./:]; a custom alphabet missing some characters present in the data; whitespace or delimiters not stripped.","commonSituations":"Decoding EU Digital COVID Certificate data with non-standard wrapping; whitespace/newlines in pasted input when removal is off; custom alphabet typo.","solutions":["Enable 'Remove non-alphabet chars' to strip stray characters automatically.","Clean the input to contain only alphabet characters before decoding.","If using a custom alphabet, ensure it contains every character present in the input."],"exampleFix":"// before: removal disabled, dirty input\nfromBase45.run('GG5A-CC..\\n', [ALPHABET, false]) // '-' not in alphabet\n// after: enable removal or pre-clean\nfromBase45.run('GG5A-CC..\\n', [ALPHABET, true])","handlingStrategy":"validation","validationCode":"// If removal is disabled, pre-filter input to alphabet chars only\nconst alphabet = Utils.expandAlphRange(args[0]).join('');\nif (!args[1]) {\n  input = input.split('').filter(c => alphabet.includes(c)).join('');\n}","typeGuard":"function onlyAlphabetChars(s, alphabet) {\n  return s.split('').every(c => alphabet.includes(c));\n}","tryCatchPattern":"try {\n  fromBase45.run(input, args);\n} catch (e) {\n  if (e.type === 'OperationError' && /Character not in alphabet/.test(e.message)) {\n    // enable 'Remove non-alphabet chars' or clean the input\n  } else throw e;\n}","preventionTips":["Keep 'Remove non-alphabet chars' enabled for noisy input.","Pre-trim whitespace and delimiters before decoding.","Ensure any custom alphabet contains every input character."],"tags":["base45","alphabet","input-validation","parsing"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}