apache/iceberg · warning

Unclosed input stream created by

Error message

Unclosed input stream created by:
	{}

What it means

GCSInputStream.finalize detects that the stream was garbage-collected without close() ever being called. As a last resort it closes the underlying GCS read channel to release the connection, and logs this warning including the creation-time stack trace so the developer can find the leak site.

Solutions

  1. Wrap the stream in try-with-resources so close() is always called
  2. Follow the stack trace in the warning to the leak site and add close/finally
  3. Check exception paths that bypass close (e.g. close only on success)
  4. After fixing, confirm the warning no longer appears in logs

Example fix

// before
InputStream in = file.newStream();
byte[] data = in.readAllBytes();
// after
try (InputStream in = file.newStream()) {
  byte[] data = in.readAllBytes();
}
Defensive patterns

Strategy: try-catch

Try / catch

try (InputStream in = file.newStream()) { consume(in); } catch (IOException e) { throw new UncheckedIOException(e); }

Prevention

When it happens

Trigger: Creating a GCSInputStream via GCSFileIO.newInputFile(...).newStream() and never calling close(), then letting it become unreachable; e.g. missing try-with-resources or an exception path skipping close.

Common situations: Reading data files or manifests with ad-hoc code that omits try-with-resources; early returns/exceptions between open and close; leaking streams in UDFs or Spark task code.

Related errors


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

Appendix: source

Thrown at gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSInputStream.java:223

  }

  @Override
  public void close() throws IOException {
    super.close();
    closed = true;
    if (channel != null) {
      channel.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 input stream created by:\n\t{}", trace);
    }
  }
}

View on GitHub (pinned to 86d9c8fc54)