{"record":{"id":"16b19315a15c3d53","repo":"apache/iceberg","slug":"failed-to-encrypt-block-expected-plaintextlengt","errorCode":null,"errorMessage":"Failed to encrypt block: expected ${plaintextLength} encrypted bytes but produced bytes ${enciphered}","messagePattern":"Failed to encrypt block: expected (.+?) encrypted bytes but produced bytes (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/encryption/Ciphers.java","lineNumber":106,"sourceCode":"\n      try {\n        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH_BITS, nonce);\n        cipher.init(Cipher.ENCRYPT_MODE, aesKey, spec);\n        if (null != aad) {\n          cipher.updateAAD(aad);\n        }\n\n        // doFinal encrypts and adds a GCM tag. The nonce is added later.\n        enciphered =\n            cipher.doFinal(\n                plaintext,\n                plaintextOffset,\n                plaintextLength,\n                ciphertextBuffer,\n                ciphertextOffset + NONCE_LENGTH);\n\n        if (enciphered != plaintextLength + GCM_TAG_LENGTH) {\n          throw new RuntimeException(\n              \"Failed to encrypt block: expected \"\n                  + plaintextLength\n                  + GCM_TAG_LENGTH\n                  + \" encrypted bytes but produced bytes \"\n                  + enciphered);\n        }\n      } catch (GeneralSecurityException e) {\n        throw new RuntimeException(\"Failed to encrypt\", e);\n      }\n\n      // Add the nonce\n      System.arraycopy(nonce, 0, ciphertextBuffer, ciphertextOffset, NONCE_LENGTH);\n\n      return enciphered + NONCE_LENGTH;\n    }\n  }\n\n  public static class AesGcmDecryptor {","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/encryption/Ciphers.java#L88-L124","documentation":"AfterCipher.doFinal, Ciphers.encrypt verifies the cipher produced exactly plaintextLength + GCM_TAG_LENGTH bytes (ciphertext plus 16-byte auth tag). Any other count means the JCE provider misbehaved, so it throws RuntimeException. Note the message itself has a string-concatenation bug: the tag length is appended directly to the number rather than summed.","triggerScenarios":"A JCE provider returning an unexpected output length from AES/GCM/NoPadding doFinal during encrypt() — essentially never with standard JDK providers.","commonSituations":"Non-standard or buggy third-party security providers; custom JVM crypto instrumentation; running on an unusual JDK with a defective GCM implementation.","solutions":["Verify the JVM's security providers; remove or fix any custom JCE provider overriding AES/GCM","Run on a standard, up-to-date JDK","Report to the provider vendor if a third-party provider is required"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  cipherOut.write(data);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Failed to encrypt block\")) {\n    // JCE provider bug: log provider info and fail fast\n    log.error(\"Provider: {}\", Security.getProviders());\n  }\n  throw e;\n}","preventionTips":["Use stock JDK security providers for AES/GCM","Avoid third-party JCE providers unless validated","Pin to a mainstream, current JDK"],"tags":["encryption","crypto","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}