apache/iceberg · error · UncheckedIOException

Failed to close iterable

Error message

Failed to close iterable

What it means

BaseDeleteLoader.materialize eagerly copies a CloseableIterable into an in-memory list so the loaded delete entries can be cached. When closing the underlying iterable's resources (file handles/readers) fails with an IOException, it is rethrown as an UncheckedIOException with this message. The delete entries were likely already read; only resource cleanup failed.

Source

Thrown at data/src/main/java/org/apache/iceberg/data/BaseDeleteLoader.java:136

  private Iterable<StructLike> readEqDeletes(DeleteFile deleteFile, Schema projection) {
    CloseableIterable<Record> deletes = openDeletes(deleteFile, projection);
    CloseableIterable<Record> copiedDeletes = CloseableIterable.transform(deletes, Record::copy);
    CloseableIterable<StructLike> copiedDeletesAsStructs = toStructs(copiedDeletes, projection);
    return materialize(copiedDeletesAsStructs);
  }

  private CloseableIterable<StructLike> toStructs(
      CloseableIterable<Record> records, Schema schema) {
    InternalRecordWrapper wrapper = new InternalRecordWrapper(schema.asStruct());
    return CloseableIterable.transform(records, wrapper::copyFor);
  }

  // materializes the iterable and releases resources so that the result can be cached
  private <T> Iterable<T> materialize(CloseableIterable<T> iterable) {
    try (CloseableIterable<T> closeableIterable = iterable) {
      return ImmutableList.copyOf(closeableIterable);
    } catch (IOException e) {
      throw new UncheckedIOException("Failed to close iterable", e);
    }
  }

  /**
   * Loads the content of a deletion vector or position delete files for a given data file path into
   * a position index.
   *
   * <p>The deletion vector is currently loaded without caching as the existing Puffin reader
   * requires at least 3 requests to fetch the entire file. Caching a single deletion vector may
   * only be useful when multiple data file splits are processed on the same node, which is unlikely
   * as task locality is not guaranteed.
   *
   * <p>For position delete files, however, there is no efficient way to read deletes for a
   * particular data file. Therefore, caching may be more effective as such delete files potentially
   * apply to many data files, especially in unpartitioned tables and tables with deep partitions.
   * If a position delete file qualifies for caching, this method will attempt to cache a position
   * index for each referenced data file.
   *

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check the chained cause (getCause()) for the real storage/IO error and fix storage connectivity/permissions.
  2. Retry the delete-file load; transient network failures on close are often recoverable.
  3. Verify the FileIO configuration (timeouts, credentials, endpoint) matches the storage system.
  4. If it persists, check for a FileIO implementation bug and report with the cause stack.

Example fix

// before: unhandled transient close failure kills the read
Iterable<Record> deletes = loader.readEqDeletes(deleteFiles);

// after: retry transient IO failures
try {
  Iterable<Record> deletes = loader.readEqDeletes(deleteFiles);
} catch (UncheckedIOException e) {
  // inspect e.getCause(); retry with backoff or fail the task with the cause
  throw new RuntimeException("Retry delete load", e.getCause());
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  Iterable<T> deletes = loader.readEqDeletes(deleteFiles);
} catch (UncheckedIOException e) {
  Throwable cause = e.getCause();
  if (isTransient(cause)) { retryWithBackoff(); } else { throw e; }
}

Prevention

When it happens

Trigger: Calling readEqDeletes/readPosDeletes (e.g. via DeleteFilter.applyEqDeletes/applyPosDeletes) when the deletion vector or position delete file's closeable iterator cannot release its underlying input stream — typically an I/O error on the underlying FileIO during close.

Common situations: Underlying storage (HDFS/S3/local FS) errors or timeouts while closing a delete-file reader; FileIO implementations that validate checksums or flush on close; network interruptions during scan of delete files.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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