{"record":{"id":"eba54e872062e216","repo":"apache/iceberg","slug":"key-generation-is-not-supported-in-this-kmsclient","errorCode":null,"errorMessage":"Key generation is not supported in this KmsClient","messagePattern":"Key generation is not supported in this KmsClient","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/encryption/KmsClient.java","lineNumber":64,"sourceCode":"   * @return true if KMS server supports key generation and KmsClient implementation is interested\n   *     to leverage this capability. Otherwise, return false - Iceberg will then generate secret\n   *     keys locally (using the SecureRandom mechanism) and call {@link #wrapKey(ByteBuffer,\n   *     String)} to wrap them in KMS.\n   */\n  default boolean supportsKeyGeneration() {\n    return false;\n  }\n\n  /**\n   * Generate a new secret key in the KMS server, and wrap it using a wrapping/master key which is\n   * stored in KMS and referenced by an ID. This method will be called only if supportsKeyGeneration\n   * returns true.\n   *\n   * @param wrappingKeyId a key ID that represents a wrapping key stored in KMS\n   * @return key in two forms: raw, and wrapped with the given wrappingKeyId\n   */\n  default KeyGenerationResult generateKey(String wrappingKeyId) {\n    throw new UnsupportedOperationException(\"Key generation is not supported in this KmsClient\");\n  }\n\n  /**\n   * Unwrap a secret key, using a wrapping/master key which is stored in KMS and referenced by an\n   * ID.\n   *\n   * @param wrappedKey wrapped key material (encrypted key and optional KMS metadata, returned by\n   *     the wrapKey method)\n   * @param wrappingKeyId a key ID that represents a wrapping key stored in KMS\n   * @return raw key bytes\n   */\n  ByteBuffer unwrapKey(String wrappedKey, String wrappingKeyId);\n\n  /**\n   * Initialize the KMS client with given properties\n   *\n   * @param properties kms client properties\n   */","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/encryption/KmsClient.java#L46-L82","documentation":"KmsClient is the pluggable interface Iceberg uses to talk to a key management service. generateKey has a default implementation that throws UnsupportedOperationException because most KMS integrations only wrap/unwrap customer-managed keys and cannot create new data keys. Multi-key (hybrid) encryption requires a KmsClient that implements key generation (e.g., AWS KMS with GenerateDataKey).","triggerScenarios":"Running encryption with a key-splitting/multi-key enclosure that calls kms.generateKey(wrappingKeyId) while the configured KmsClient only implements wrap/unwrap (the default method is hit).","commonSituations":"Configuring table encryption with write.metadata.metrics / encryption properties using a basic KMS plugin that lacks key-generation; using a mock or custom KmsClient in tests; older catalog KMS adapters that predate key generation support.","solutions":["Configure a KmsClient implementation that supports key generation and returns true for supportsKeyGeneration() (e.g., the AWS KMS client based on GenerateDataKey).","If multi-key encryption is not required, use single-key encryption with kms.wrapKey so generateKey is never invoked.","Implement generateKey in your custom KmsClient, producing a raw key plus a key wrapped with the given wrappingKeyId.","Update your encryption configuration to avoid key splitting (reduce key length/number of keys so the basic path is used).","Guard feature-detection: check supportsKeyGeneration() before enabling multi-key encryption."],"exampleFix":"// before\ncatalog.properties: io.manifest.cache ... \nEncryptedOutputFile out = encryptedIO.newEncryptingOutputFile(...); // uses multi-key path -> generateKey -> throws\n// after\npublic class AwsKmsClient implements KmsClient {\n  @Override\n  public boolean supportsKeyGeneration() {\n    return true;\n  }\n\n  @Override\n  public KeyGenerationResult generateKey(String wrappingKeyId) {\n    GenerateDataKeyResult r = kms.generateDataKey(...);\n    return new KeyGenerationResult(ByteBuffer.wrap(r.getPlaintext()), ByteBuffer.wrap(r.getCiphertextBlob()));\n  }\n}","handlingStrategy":"try-catch","validationCode":"boolean closeable = encryptionManager instanceof Closeable;\nif (!closeable) { io.close(); return; }","typeGuard":"boolean safelyCloseable(Object em) {\n  return em instanceof Closeable;\n}","tryCatchPattern":"try {\n  io.close();\n} catch (UncheckedIOException e) {\n  if (\"Failed to close encryption manager\".equals(e.getMessage())) {\n    LOG.warn(\"encryption manager cleanup failed\", e.getCause());\n  } else {\n    throw e;\n  }\n}","preventionTips":["Close all streams from the encrypted IO before closing the IO itself.","Don't swallow this during shutdown; log the cause for the root resource issue.","Avoid double-closing encryption managers.","Keep KMS/crypto plugins on supported versions whose close() is reliable."],"tags":["encryption","kms","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}