{"record":{"id":"235375491272287b","repo":"gchq/CyberChef","slug":"triplet-too-large-triple-join","errorCode":null,"errorMessage":"Triplet too large: '${triple.join(\"\")}'","messagePattern":"Triplet too large: '(.+?)'","errorType":"exception","errorClass":"OperationError","httpStatus":null,"severity":"error","filePath":"src/core/operations/FromBase45.mjs","lineNumber":78,"sourceCode":"        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            /**\n             * Pushing LSB\n             */\n            res.push(b & 0xff);\n\n        }\n\n        return res;","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/gchq/CyberChef/blob/4290ea753912378913b1f3f54e0fc5720afeda5d/src/core/operations/FromBase45.mjs#L60-L96","documentation":"Thrown by From Base45 when a decoded triplet value exceeds 65535, which cannot fit in the two output bytes Base45 expects per triplet. In valid Base45, a full triplet's combined value (after reversing and accumulating b*45+idx) must be <= 0xFFFF. Exceeding it indicates corrupted or non-Base45 input that survived character validation.","triggerScenarios":"Input that is structurally triplet-aligned and uses valid alphabet characters but whose values combine to > 65535 (e.g. three high-value chars); truncated/reordered Base45; data that looks like Base45 but is actually a different base with overlapping characters.","commonSituations":"Misidentified encoding (Base58/Base64 data fed as Base45); partially edited Base45 string; concatenation of two Base45 blobs without re-encoding.","solutions":["Confirm the data is genuinely Base45 (e.g. from a QR code / EU DCC).","If the data is another base, switch to the correct From Base operation.","Re-encode or re-extract the source to ensure triplet integrity."],"exampleFix":"// before: Base64-looking data fed as Base45\nfromBase45.run(base64String, [ALPHABET, true]) // triplet overflows\n// after: use the correct decoder\nfromBase64.run(base64String, ...)","handlingStrategy":"validation","validationCode":"// Heuristic: valid Base45 triplets decode to <= 65535; if you control the source,\n// verify the input length is a multiple that aligns with Base45 grouping.\nconst alphabet = Utils.expandAlphRange(args[0]).join('');\n// cannot fully pre-validate without decoding, but confirm input is the right encoding\nif (!/^[0-9A-Z $%*+\\-./:]+$/.test(input)) {\n  // likely not Base45; choose another decoder\n}","typeGuard":null,"tryCatchPattern":"try {\n  fromBase45.run(input, args);\n} catch (e) {\n  if (e.type === 'OperationError' && /Triplet too large/.test(e.message)) {\n    // data is probably not Base45; try From Base58/64 instead\n  } else throw e;\n}","preventionTips":["Confirm the source genuinely uses Base45 (e.g. EU DCC QR payloads).","If triplet overflow occurs, suspect a misidentified encoding.","Re-extract the source payload to avoid truncation/reordering."],"tags":["base45","decode","data-corruption","range"],"backgroundTag":null,"analyzedSha":"4290ea753912378913b1f3f54e0fc5720afeda5d","analyzedAt":"2026-08-13T06:05:50.210Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}