{"record":{"id":"0193bf796cc01b57","repo":"mastra-ai/mastra","slug":"invalid-ciphertext-payload","errorCode":null,"errorMessage":"Invalid ciphertext payload","messagePattern":"Invalid ciphertext payload","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/slack/src/crypto.ts","lineNumber":92,"sourceCode":"\n/**\n * Decrypt data produced by encrypt().\n */\nexport function decrypt(ciphertext: string, key: string): string {\n  const colonIdx = ciphertext.indexOf(':');\n  if (colonIdx === -1) {\n    throw new Error('Invalid ciphertext format');\n  }\n\n  const prefix = ciphertext.slice(0, colonIdx);\n  if (prefix !== ALGO_PREFIX) {\n    throw new Error(`Unsupported encryption algorithm: ${prefix}`);\n  }\n\n  const payload = ciphertext.slice(colonIdx + 1);\n  const [saltB64, ivB64, authTagB64, encryptedB64] = payload.split(':');\n  if (!saltB64 || !ivB64 || !authTagB64 || encryptedB64 === undefined) {\n    throw new Error('Invalid ciphertext payload');\n  }\n\n  const salt = Buffer.from(saltB64, 'base64');\n  const derived = Buffer.from(hkdfSync('sha256', key, salt, 'mastra-slack-encryption', 32));\n  const iv = Buffer.from(ivB64, 'base64');\n  const authTag = Buffer.from(authTagB64, 'base64');\n  const encrypted = Buffer.from(encryptedB64, 'base64');\n\n  const decipher = createDecipheriv('aes-256-gcm', derived, iv);\n  decipher.setAuthTag(authTag);\n  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString('utf8');\n}\n","sourceCodeStart":74,"sourceCodeEnd":105,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/slack/src/crypto.ts#L74-L105","documentation":"After the algorithm prefix matches, decrypt() splits the remainder on ':' and requires exactly the four base64 segments salt, iv, authTag and encrypted data. If any of the first three is empty or the encrypted segment is missing, the ciphertext is malformed and cannot be decrypted.","triggerScenarios":"Calling decrypt (via #decryptPendingInstallation, #decryptInstallation, #decryptConfigTokens) with a string like 'prefix:' (empty payload), 'prefix:salt:iv' (truncated), or otherwise corrupted/truncated ciphertext missing one of the four ':'-separated base64 parts.","commonSituations":"Database column truncation cutting off the tail of the value; manual edits to stored records; copy/paste dropping characters; a value stored by an incompatible writer.","solutions":["Re-store the value using encrypt() so it is a complete 'prefix:salt:iv:authTag:encrypted' string.","Check the storage column size/type and ensure the full ciphertext was persisted (no truncation).","Delete the corrupt record and re-run the Slack connect/installation flow to regenerate it."],"exampleFix":"// before (truncated column)\nCREATE TABLE installs (bot_token TEXT(50));\n// after\nCREATE TABLE installs (bot_token TEXT);","handlingStrategy":"validation","validationCode":"function isWellFormedCiphertext(v) {\n  if (typeof v !== 'string') return false;\n  const parts = v.split(':');\n  return parts.length === 5 && parts.slice(1, 4).every(Boolean) && parts[4] !== undefined;\n}\nif (!isWellFormedCiphertext(stored)) throw new Error('stored ciphertext is truncated or malformed');","typeGuard":"function hasFiveSegments(v: unknown): v is string {\n  return typeof v === 'string' && v.split(':').length === 5;\n}","tryCatchPattern":"try {\n  const token = await decrypt(stored);\n} catch (err) {\n  if (err instanceof Error && err.message === 'Invalid ciphertext payload') {\n    logger.error('corrupt ciphertext in storage, re-running installation');\n    await reRunSlackInstallation(agentId);\n  } else throw err;\n}","preventionTips":["Use TEXT (unbounded) columns for ciphertext to avoid truncation.","Round-trip test: decrypt(encrypt(v)) === v in CI.","Back up storage before manual edits to encrypted records."],"tags":["crypto","decryption","data-corruption"],"backgroundTag":"invalid-ciphertext-payload","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}