mastra-ai/mastra · error
Invalid ciphertext payload
Error message
Invalid ciphertext payload
What it means
decrypt() in channels/telegram recognizes an encrypted value by its 'salt:iv:tag:ciphertext' base64 prefix format. If the value carries the encrypted marker but splitting yields empty salt/iv/tag or missing ciphertext, the payload is structurally corrupt and cannot be AES-256-GCM decrypted, so the function throws. Note plaintext (unprefixed) values pass through unchanged by design.
Source
Thrown at channels/telegram/src/crypto.ts:40
return value.startsWith(`${ALGO_PREFIX}:`);
}
/** Encrypt a UTF-8 string with a per-value random salt + IV. */
export function encrypt(plaintext: string, passphrase: string): string {
const salt = randomBytes(16);
const iv = randomBytes(12);
const cipher = createCipheriv('aes-256-gcm', deriveKey(passphrase, salt), iv);
const enc = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
const tag = cipher.getAuthTag();
return `${ALGO_PREFIX}:${salt.toString('base64')}:${iv.toString('base64')}:${tag.toString('base64')}:${enc.toString('base64')}`;
}
/** Decrypt a value from {@link encrypt}. Plaintext (unprefixed) is returned unchanged. */
export function decrypt(value: string, passphrase: string): string {
if (!isEncrypted(value)) return value;
const [, saltB64, ivB64, tagB64, ctB64] = value.split(':');
if (!saltB64 || !ivB64 || !tagB64 || ctB64 === undefined) {
throw new Error('Invalid ciphertext payload');
}
const decipher = createDecipheriv(
'aes-256-gcm',
deriveKey(passphrase, Buffer.from(saltB64, 'base64')),
Buffer.from(ivB64, 'base64'),
);
decipher.setAuthTag(Buffer.from(tagB64, 'base64'));
return Buffer.concat([decipher.update(Buffer.from(ctB64, 'base64')), decipher.final()]).toString('utf8');
}
View on GitHub (pinned to 75dd419e61)
Solutions
- Re-encrypt and store the secret: delete the corrupt record and re-save the bot token (or re-run the install flow) so a fresh valid ciphertext is written.
- Verify the stored string has exactly the format enc:salt:iv:tag:ciphertext with valid base64 segments and no truncation.
- Widen the storage column (e.g. TEXT) if a fixed-length column truncated the value.
- Confirm the value was produced by this library's encrypt() and not another tool with a similar prefix.
Example fix
// before (truncated value in DB)
await store.save({ botToken: 'v1:YWJj' }); // corrupt
// after
const botToken = encrypt(realToken, encryptionKey); // full enc:salt:iv:tag:ct
await store.save({ botToken }); Defensive patterns
Strategy: validation
Validate before calling
function looksLikeCorruptCiphertext(v: string): boolean {
if (!v.startsWith('enc:')) return false; // adjust to actual prefix
const parts = v.split(':');
return parts.length < 5 || parts.slice(1, 4).some(p => !p) || parts[4] === undefined;
} Try / catch
try {
const token = store.getBotToken(recordId);
} catch (e) {
if (e instanceof Error && e.message === 'Invalid ciphertext payload') {
await reEncryptAndStore(recordId); // prompt re-install / re-save secret
} else throw e;
} Prevention
- Store encrypted secrets in a TEXT/bytea column sized for the full ciphertext.
- Never hand-edit or partially copy encrypted values.
- Re-encrypt records when upgrading encryption formats or libraries.
When it happens
Trigger: Calling decrypt() (indirectly via TelegramInstallationStore #dec) on a stored secret that is prefixed as encrypted but has truncated/malformed segments — e.g. a value truncated by a fixed-length DB column, hand-edited, or encrypted by a different/incompatible format version.
Common situations: DB migration truncating the stored ciphertext; someone pasting a partially copied encrypted string into config; mixing outputs from different encryption implementations that share the prefix but differ in layout.
Related errors
- Telegram installation secrets are encrypted at rest, but no
- Invalid encrypted session data
- Cookie password must be at least 32 characters for SSO. Set
- Invalid encrypted session data
- Cookie password must be at least 32 characters for SSO. Set
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/250ec60ded3e9688.
Report an issue: GitHub.