{"record":{"id":"fc9ef4e9a4698845","repo":"apache/iceberg","slug":"unclosed-output-stream-created-by-n-t","errorCode":null,"errorMessage":"Unclosed output stream created by:\\n\\t{}","messagePattern":"Unclosed output stream created by:\\\\n\\\\t(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"aws/src/main/java/org/apache/iceberg/aws/s3/S3OutputStream.java","lineNumber":490,"sourceCode":"              \"Successfully created staging directory by another process: {}\",\n              stagingDirectory.getAbsolutePath());\n        } else {\n          throw new IOException(\n              \"Failed to create staging directory due to some unknown reason: \"\n                  + stagingDirectory.getAbsolutePath());\n        }\n      }\n    }\n  }\n\n  @SuppressWarnings({\"checkstyle:NoFinalizer\", \"Finalize\", \"deprecation\"})\n  @Override\n  protected void finalize() throws Throwable {\n    super.finalize();\n    if (!closed) {\n      close(false); // releasing resources is more important than printing the warning\n      String trace = Joiner.on(\"\\n\\t\").join(Arrays.copyOfRange(createStack, 1, createStack.length));\n      LOG.warn(\"Unclosed output stream created by:\\n\\t{}\", trace);\n    }\n  }\n\n  private static class FileAndDigest {\n    private final File file;\n    private final MessageDigest digest;\n\n    FileAndDigest(File file, MessageDigest digest) {\n      this.file = file;\n      this.digest = digest;\n    }\n\n    File file() {\n      return file;\n    }\n\n    byte[] digest() {\n      return digest.digest();","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/aws/src/main/java/org/apache/iceberg/aws/s3/S3OutputStream.java#L472-L508","documentation":"S3OutputStream registers its creation stack trace and, in finalize(), detects that the stream was never closed. It force-closes the stream to release resources and logs a WARN containing the creation stack so the developer can find where the unclosed stream was allocated.","triggerScenarios":"Creating an S3OutputStream (via FileIO.newOutputFile().createOrOverwrite()) and never calling close(), e.g. an exception path that skips the finally block, or holding the stream past garbage collection.","commonSituations":" Forgotten try-with-resources around output writes; exception thrown between create and close; leaks when writing table metadata/manifests in ad-hoc tools.","solutions":["Wrap usage in try-with-resources so close() is always invoked","Use the createStack in the warning to locate the allocation site and add proper close handling","Ensure error paths don't abandon the stream before writing completes"],"exampleFix":"// before\nOutputFile out = io.newOutputFile(path);\nS3OutputStream os = (S3OutputStream) out.createOrOverwrite();\nos.write(data);\n// after\ntry (S3OutputStream os = (S3OutputStream) io.newOutputFile(path).createOrOverwrite()) {\n  os.write(data);\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try (S3OutputStream os = (S3OutputStream) outputFile.createOrOverwrite()) {\n  os.write(data);\n} // auto-close; finalize warning cannot occur","preventionTips":["Always use try-with-resources for FileIO output streams","Use the creation stack in the WARN to fix leak sites in custom tools","Check for missing close on exception paths and early returns"],"tags":["aws","s3","resource-leak","unclosed-stream"],"backgroundTag":"unclosed-stream-resource-leak","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"}