apache/iceberg · warning

Unclosed output stream created by

Error message

Unclosed output stream created by:
	{}

What it means

GCSOutputStream.finalize detects that an output stream (used when writing files to GCS) was never closed before garbage collection. It closes the stream as a safety net — which for GCS may abort or complete the upload — and logs this warning with the creation stack trace to point at the leak.

Solutions

  1. Always use try-with-resources around the output stream
  2. Use the stack trace in the warning to locate and fix the unclosed write
  3. Ensure close() (not just flush()) is called so the GCS upload finalizes
  4. Note: without close(), the written file may be incomplete — re-verify data after fixing

Example fix

// before
OutputStream out = outF.create();
out.write(bytes);
// after
try (OutputStream out = outF.create()) {
  out.write(bytes);
}
Defensive patterns

Strategy: try-catch

Try / catch

try (OutputStream out = outputFile.createOrOverwrite()) { out.write(bytes); } catch (IOException e) { throw new UncheckedIOException(e); }

Prevention

When it happens

Trigger: Calling GCSFileIO.newOutputFile(...).create(...) or createOrOverwrite(...) and never invoking close() on the returned OutputStream, letting GC finalize it.

Common situations: Custom writers that forget try-with-resources; exceptions thrown between create and close; writing metadata/data files in scripts or tests without proper cleanup.

Related errors


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

Appendix: source

Thrown at gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSOutputStream.java:140

  @Override
  public void close() throws IOException {
    if (closed) {
      return;
    }

    super.close();
    closed = true;
    stream.close();
  }

  @SuppressWarnings({"checkstyle:NoFinalizer", "Finalize", "deprecation"})
  @Override
  protected void finalize() throws Throwable {
    super.finalize();
    if (!closed) {
      close(); // 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);
    }
  }
}

View on GitHub (pinned to 86d9c8fc54)