{"record":{"id":"08a224d6ba161739","repo":"apache/iceberg","slug":"failed-to-close-encryption-manager","errorCode":null,"errorMessage":"Failed to close encryption manager","messagePattern":"Failed to close encryption manager","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/org/apache/iceberg/encryption/EncryptingFileIO.java","lineNumber":179,"sourceCode":"  @Override\n  public void deleteFile(String path) {\n    io.deleteFile(path);\n  }\n\n  @Override\n  public Map<String, String> properties() {\n    return io.properties();\n  }\n\n  @Override\n  public void close() {\n    io.close();\n\n    if (em instanceof Closeable) {\n      try {\n        ((Closeable) em).close();\n      } catch (IOException e) {\n        throw new UncheckedIOException(\"Failed to close encryption manager\", e);\n      }\n    }\n  }\n\n  private SimpleEncryptedInputFile wrap(ContentFile<?> file) {\n    InputFile encryptedInputFile = io.newInputFile(file.location(), file.fileSizeInBytes());\n    return new SimpleEncryptedInputFile(encryptedInputFile, toKeyMetadata(file.keyMetadata()));\n  }\n\n  private static SimpleEncryptedInputFile wrap(InputFile encryptedInputFile, ByteBuffer buffer) {\n    return new SimpleEncryptedInputFile(encryptedInputFile, toKeyMetadata(buffer));\n  }\n\n  private static EncryptionKeyMetadata toKeyMetadata(ByteBuffer buffer) {\n    return buffer != null ? new SimpleKeyMetadata(buffer) : EncryptionKeyMetadata.empty();\n  }\n\n  private static class SimpleEncryptedInputFile implements EncryptedInputFile {","sourceCodeStart":161,"sourceCodeEnd":197,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/encryption/EncryptingFileIO.java#L161-L197","documentation":"EncryptingFileIO.close() closes the wrapped FileIO and then the encryption manager if it is Closeable. If closing the encryption manager's underlying resources (key streams, native handles) raises IOException, it is rethrown as UncheckedIOException with this message. This indicates the encrypted-IO layer could not shut down cleanly.","triggerScenarios":"Calling close() on an EncryptingFileIO (e.g., via try-with-resources or Hadoop FileSystem/CloseableGroup shutdown) when the underlying encryption manager's close() throws IOException.","commonSituations":"Shutting down a job whose encryption manager holds open native crypto contexts (e.g., a C++/native KMS client or encrypted-file handles that fail to release); cleanup during error paths where an earlier failure left the manager in a bad state.","solutions":["Inspect the wrapped IOException cause to find the real failure in the encryption manager (native handle, stream, or file lock) and fix that root cause.","Ensure all input/output streams opened through the EncryptingFileIO are closed before closing the IO itself.","Upgrade or reconfigure the encryption manager/KMS plugin; some implementations are not safely closeable and leak resources.","If this occurs during shutdown after a primary failure, log it as suppressed cleanup noise rather than masking the original exception.","Verify the encryption manager instance is not being closed twice (double-close can throw in some implementations)."],"exampleFix":"// before\ntry (EncryptingFileIO io = EncryptingFileIO.combine(table.io(), enclosure)) {\n  ... // exception thrown mid-way; close() then fails closing the encryption manager\n}\n// after\ntry (EncryptingFileIO io = EncryptingFileIO.combine(table.io(), enclosure)) {\n  ...\n} catch (RuntimeException primary) {\n  try {\n    io.close();\n  } catch (UncheckedIOException cleanup) {\n    primary.addSuppressed(cleanup.getCause());\n  }\n  throw primary;\n}","handlingStrategy":"try-catch","validationCode":"Class<?> c = sessionCatalog.getClass();\nMethod m = c.getMethod(\"registerView\", SessionCatalog.SessionContext.class, TableIdentifier.class, String.class);\nboolean supported = m.getDeclaringClass() != ViewSessionCatalog.class; // overridden by impl","typeGuard":"boolean supportsRegisterView(ViewSessionCatalog catalog) {\n  try {\n    return !ViewSessionCatalog.class\n        .getDeclaredMethod(\"registerView\", SessionCatalog.SessionContext.class, TableIdentifier.class, String.class)\n        .equals(catalog.getClass().getMethod(\"registerView\",\n            SessionCatalog.SessionContext.class, TableIdentifier.class, String.class));\n  } catch (NoSuchMethodException e) {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  view = sessionCatalog.registerView(context, ident, metadataLocation);\n} catch (UnsupportedOperationException e) {\n  throw new IllegalStateException(\"View registration unsupported for session catalog \" + name, e);\n}","preventionTips":["Check whether the underlying catalog overrides registerView before routing view registration through a session wrapper.","Recreate views rather than registering metadata files in session-catalog flows.","Wrap shared registerTable/registerView code paths with per-capability checks."],"tags":["io","encryption","resource-cleanup","unchecked-ioexception"],"backgroundTag":"file-write-failed","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"}