gchq/CyberChef · error · OperationError
Letter ${letter} is not in the key
Error message
Letter ${letter} is not in the key What it means
findPos(key, letter) maps a plaintext/ciphertext character to a [row, col] coordinate on the 7x7 key tile grid. If the character is not present in the key string (indexOf === -1) or the index is out of the 0..48 range, it throws. Because the valid key is a permutation of the LS47 alphabet, this effectively rejects any input character outside "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()".
Source
Thrown at src/core/lib/LS47.mjs:123
throw new OperationError("Letter " + elem + " not in LS47");
counts[elem]++;
if (counts[elem] > 1)
throw new OperationError("Letter duplicated in the key");
}
}
/**
* Finds the position of a letter in they key.
*
* @param {letter} key
* @param {string} letter
* @returns {object}
*/
function findPos (key, letter) {
const index = key.indexOf(letter);
if (index >= 0 && index < 49)
return [Math.floor(index/7), index%7];
throw new OperationError("Letter " + letter + " is not in the key");
}
/**
* Returns the character at the position on the tiles.
*
* @param {string} key
* @param {object} coord
* @returns {string}
*/
function findAtPos(key, coord) {
return key.charAt(coord[1] + (coord[0] * 7));
}
/**
* Returns new position by adding two positions.
*
* @param {object} a
* @param {object} bView on GitHub (pinned to 4290ea7539)
Solutions
- Sanitize input to only LS47-alphabet characters before encrypting: input.replace(/[^_a-z0-9.,\-+*/:?!'()]/g, '').
- Lowercase any alphabetic input and substitute or strip unsupported punctuation.
- Verify the ciphertext comes from the same LS47 alphabet before calling decrypt.
- Confirm you are using the correct key and that the ciphertext was not transformed by another operation.
Example fix
// before const ct = LS47.encrypt(key, "Hello World"); // 'H',' ','W' not in alphabet // after const clean = plaintext.toLowerCase().replace(/[^_a-z0-9.,\-+*/:?!'()]/g, ''); const ct = LS47.encrypt(key, clean);
Defensive patterns
Strategy: validation
Validate before calling
const LS47_ALPHABET = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
function sanitizeLS47Input(s) {
return s.toLowerCase().replace(/[^_a-z0-9.,\-+*/:?!'()]/g, '');
}
const clean = sanitizeLS47Input(plaintext);
const ct = LS47.encrypt(key, clean); Type guard
function isLS47AlphabetString(x): x is string {
const A = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()";
return typeof x === 'string' && [...x].every(c => A.includes(c));
} Try / catch
try {
return LS47.encrypt(key, plaintext);
} catch (e) {
if (e instanceof OperationError && /is not in the key/.test(e.message)) {
throw new Error('Input contains a character outside the LS47 alphabet: ' + e.message);
}
throw e;
} Prevention
- Lowercase and strip non-alphabet characters from input before encrypting.
- Verify ciphertext integrity and alphabet before decrypting.
- Chain a 'Remove non-alphabet chars' or 'Replace' operation in CyberChef before LS47 encrypt.
- Confirm the upstream operation produced LS47-alphabet output.
When it happens
Trigger: Calling encrypt(key, plaintext) with a plaintext containing uppercase letters, '@', newlines, or any char not in the 49-char alphabet. Calling decrypt(key, ciphertext) with a ciphertext containing such a char (typically because the ciphertext was corrupted or the wrong key was used to partially decode).
Common situations: User feeds raw prose containing spaces or uppercase letters directly to encrypt(); input not lowercased/normalized; ciphertext mangled by transport (URL-decoding, copy-paste through formatting); wrong operation chained before LS47 decrypt.
Related errors
- Wrong key size
- Letter ${elem} not in LS47
- Letter duplicated in the key
- Letter ${letter} is not included in LS47
- Byte length must be a positive integer
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/d1a0f6404e109bd9.
Report an issue: GitHub.