apache/iceberg · warning

Unclosed output stream created by:\n\t

Error message

Unclosed output stream created by:\n\t{}

What it means

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.

Solutions

  1. Wrap usage in try-with-resources so close() is always invoked
  2. Use the createStack in the warning to locate the allocation site and add proper close handling
  3. Ensure error paths don't abandon the stream before writing completes

Example fix

// before
OutputFile out = io.newOutputFile(path);
S3OutputStream os = (S3OutputStream) out.createOrOverwrite();
os.write(data);
// after
try (S3OutputStream os = (S3OutputStream) io.newOutputFile(path).createOrOverwrite()) {
  os.write(data);
}
Defensive patterns

Strategy: try-catch

Try / catch

try (S3OutputStream os = (S3OutputStream) outputFile.createOrOverwrite()) {
  os.write(data);
} // auto-close; finalize warning cannot occur

Prevention

When it happens

Trigger: 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.

Common situations: Forgotten try-with-resources around output writes; exception thrown between create and close; leaks when writing table metadata/manifests in ad-hoc tools.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/fc9ef4e9a4698845. Report an issue: GitHub.

Appendix: source

Thrown at aws/src/main/java/org/apache/iceberg/aws/s3/S3OutputStream.java:490

              "Successfully created staging directory by another process: {}",
              stagingDirectory.getAbsolutePath());
        } else {
          throw new IOException(
              "Failed to create staging directory due to some unknown reason: "
                  + stagingDirectory.getAbsolutePath());
        }
      }
    }
  }

  @SuppressWarnings({"checkstyle:NoFinalizer", "Finalize", "deprecation"})
  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    if (!closed) {
      close(false); // releasing resources is more important than printing the warning
      String trace = Joiner.on("\n\t").join(Arrays.copyOfRange(createStack, 1, createStack.length));
      LOG.warn("Unclosed output stream created by:\n\t{}", trace);
    }
  }

  private static class FileAndDigest {
    private final File file;
    private final MessageDigest digest;

    FileAndDigest(File file, MessageDigest digest) {
      this.file = file;
      this.digest = digest;
    }

    File file() {
      return file;
    }

    byte[] digest() {
      return digest.digest();

View on GitHub (pinned to 86d9c8fc54)