{"record":{"id":"df50d706c19118cc","repo":"apache/cassandra","slug":"failed-to-decrypt-commit-log-block","errorCode":null,"errorMessage":"failed to decrypt commit log block","messagePattern":"failed to decrypt commit log block","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/security/EncryptionUtils.java","lineNumber":163,"sourceCode":"            throw new IllegalStateException(\"could not read encrypted blocked metadata header\");\n        int encryptedLength = metadataBuffer.getInt();\n        // this is the length of the compressed data\n        int plainTextLength = metadataBuffer.getInt();\n\n        outputBuffer = ByteBufferUtil.ensureCapacity(outputBuffer, Math.max(plainTextLength, encryptedLength), allowBufferResize);\n        outputBuffer.position(0).limit(encryptedLength);\n        channel.read(outputBuffer);\n\n        ByteBuffer dupe = outputBuffer.duplicate();\n        dupe.clear();\n\n        try\n        {\n            cipher.doFinal(outputBuffer, dupe);\n        }\n        catch (ShortBufferException | IllegalBlockSizeException | BadPaddingException e)\n        {\n            throw new IOException(\"failed to decrypt commit log block\", e);\n        }\n\n        dupe.position(0).limit(plainTextLength);\n        return dupe;\n    }\n\n    // path used when decrypting commit log files\n    public static ByteBuffer decrypt(FileDataInput fileDataInput, ByteBuffer outputBuffer, boolean allowBufferResize, Cipher cipher) throws IOException\n    {\n        return decrypt(new DataInputReadChannel(fileDataInput), outputBuffer, allowBufferResize, cipher);\n    }\n\n    /**\n     * Uncompress the input data, as well as manage sizing of the {@code outputBuffer}; if the buffer is not big enough,\n     * deallocate current, and allocate a large enough buffer.\n     *\n     * @return the byte buffer that was actaully written to; it may be the {@code outputBuffer} if it had enough capacity,\n     * or it may be a new, larger instance. Callers should capture the return buffer (if calling multiple times).","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/security/EncryptionUtils.java#L145-L181","documentation":"EncryptionUtils.decrypt finishes the JCE decryption of a block with cipher.doFinal; failures (short output buffer, illegal block size, bad padding) are wrapped in IOException(\"failed to decrypt commit log block\"). This almost always means the ciphertext, key, or IV does not match what was encrypted.","triggerScenarios":"decrypt() with a cipher built for a different key_alias/IV than the block was written with, corrupted ciphertext, or a dupe/output buffer too small for the plaintext.","commonSituations":"Key rotation removing a still-needed key version, decrypting a segment with a changed transparent_data_encryption_options configuration (cipher or key_alias), or media corruption of the encrypted block.","solutions":["Confirm the current key_alias and cipher configuration match those used when the segment was written; restore the old key if it was rotated out.","Inspect the wrapped exception: BadPaddingException/IllegalBlockSizeException usually indicate wrong key or corrupted ciphertext.","Check the IV used to build the decryptor matches the block's header IV.","If the segment is damaged, restore from backup; partial block corruption is not recoverable."],"exampleFix":"// before: config changed after segments were written\ntransparent_data_encryption_options:\n  key_alias: key_v2\n// after: keep prior keys available to decrypt old segments\ntransparent_data_encryption_options:\n  key_alias: key_v2\n# ensure key_v1 still exists in the keystore for old commit log segments","handlingStrategy":"try-catch","validationCode":"// ensure the key for the segment's alias is still loadable before replaying old segments\nKeyStore ks = KeyStore.getInstance(\"JCEKS\");\ntry (InputStream in = new FileInputStream(keystorePath)) { ks.load(in, password.toCharArray()); }\nif (!ks.containsAlias(tdeOptions.key_alias)) throw new IllegalStateException(\"key removed: \" + tdeOptions.key_alias);","typeGuard":null,"tryCatchPattern":"try {\n    ByteBuffer plain = EncryptionUtils.decrypt(channel, null, true, reusableBuffers);\n} catch (IOException e) {\n    if (e.getMessage().equals(\"failed to decrypt commit log block\")) {\n        // e.getCause() BadPadding/IllegalBlockSize -> wrong key/IV or corrupt block; do not retry with same inputs\n    }\n}","preventionTips":["Retain all key versions referenced by existing encrypted segments","Freeze TDE config (cipher, key_alias) for the lifetime of existing segments","Verify checksums/integrity when moving encrypted files between hosts"],"tags":["encryption","commitlog","decryption","corruption"],"backgroundTag":"decryption-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}