apache/iceberg · warning

Unclosed input stream created by:\n\t

Error message

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

What it means

S3InputStream.finalize() detects input streams that were never close()d before garbage collection. It closes the stream (releasing the S3 connection is prioritized), then logs this warning with the creation stack trace to expose the leak. Leaked streams hold S3 connections/heap buffers until GC.

Solutions

  1. Wrap all S3InputStream usage in try-with-resources
  2. Close the stream in finally blocks on early-return paths
  3. Use the logged create-stack to find the leaking call site
  4. Prefer higher-level readers (e.g. DataFile readers) that manage stream lifecycle

Example fix

// before
InputStream in = inputFile.newStream();
return readHeader(in);
// after
try (InputStream in = inputFile.newStream()) {
  return readHeader(in);
}
Defensive patterns

Strategy: try-catch

Try / catch

try (InputStream in = inputFile.newStream()) {
  // read
} catch (IOException e) {
  throw new UncheckedIOException(e);
} // stream is always closed even on exception

Prevention

When it happens

Trigger: Code obtains an input stream from S3InputFile.newStream() and never closes it, e.g. early return/exception path skipping close, or a failed parquet/avro read that didn't close its source.

Common situations: Manual stream handling without try-with-resources; reader frameworks that abandon streams on parse errors; Spark tasks cancelled mid-read.

Related errors


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

Appendix: source

Thrown at aws/src/main/java/org/apache/iceberg/aws/s3/S3InputStream.java:317

        ((Abortable) stream).abort();
      }
    } catch (Exception e) {
      LOG.warn("An error occurred while aborting the stream", e);
    }
  }

  public void setSkipSize(int skipSize) {
    this.skipSize = skipSize;
  }

  @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)