{"record":{"id":"c77eff24c33db1e0","repo":"apache/iceberg","slug":"failed-to-close-iterable","errorCode":null,"errorMessage":"Failed to close iterable","messagePattern":"Failed to close iterable","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"data/src/main/java/org/apache/iceberg/data/BaseDeleteLoader.java","lineNumber":136,"sourceCode":"  private Iterable<StructLike> readEqDeletes(DeleteFile deleteFile, Schema projection) {\n    CloseableIterable<Record> deletes = openDeletes(deleteFile, projection);\n    CloseableIterable<Record> copiedDeletes = CloseableIterable.transform(deletes, Record::copy);\n    CloseableIterable<StructLike> copiedDeletesAsStructs = toStructs(copiedDeletes, projection);\n    return materialize(copiedDeletesAsStructs);\n  }\n\n  private CloseableIterable<StructLike> toStructs(\n      CloseableIterable<Record> records, Schema schema) {\n    InternalRecordWrapper wrapper = new InternalRecordWrapper(schema.asStruct());\n    return CloseableIterable.transform(records, wrapper::copyFor);\n  }\n\n  // materializes the iterable and releases resources so that the result can be cached\n  private <T> Iterable<T> materialize(CloseableIterable<T> iterable) {\n    try (CloseableIterable<T> closeableIterable = iterable) {\n      return ImmutableList.copyOf(closeableIterable);\n    } catch (IOException e) {\n      throw new UncheckedIOException(\"Failed to close iterable\", e);\n    }\n  }\n\n  /**\n   * Loads the content of a deletion vector or position delete files for a given data file path into\n   * a position index.\n   *\n   * <p>The deletion vector is currently loaded without caching as the existing Puffin reader\n   * requires at least 3 requests to fetch the entire file. Caching a single deletion vector may\n   * only be useful when multiple data file splits are processed on the same node, which is unlikely\n   * as task locality is not guaranteed.\n   *\n   * <p>For position delete files, however, there is no efficient way to read deletes for a\n   * particular data file. Therefore, caching may be more effective as such delete files potentially\n   * apply to many data files, especially in unpartitioned tables and tables with deep partitions.\n   * If a position delete file qualifies for caching, this method will attempt to cache a position\n   * index for each referenced data file.\n   *","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/data/src/main/java/org/apache/iceberg/data/BaseDeleteLoader.java#L118-L154","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the chained cause (getCause()) for the real storage/IO error and fix storage connectivity/permissions.","Retry the delete-file load; transient network failures on close are often recoverable.","Verify the FileIO configuration (timeouts, credentials, endpoint) matches the storage system.","If it persists, check for a FileIO implementation bug and report with the cause stack."],"exampleFix":"// before: unhandled transient close failure kills the read\nIterable<Record> deletes = loader.readEqDeletes(deleteFiles);\n\n// after: retry transient IO failures\ntry {\n  Iterable<Record> deletes = loader.readEqDeletes(deleteFiles);\n} catch (UncheckedIOException e) {\n  // inspect e.getCause(); retry with backoff or fail the task with the cause\n  throw new RuntimeException(\"Retry delete load\", e.getCause());\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  Iterable<T> deletes = loader.readEqDeletes(deleteFiles);\n} catch (UncheckedIOException e) {\n  Throwable cause = e.getCause();\n  if (isTransient(cause)) { retryWithBackoff(); } else { throw e; }\n}","preventionTips":["Use reliable FileIO implementations with sane timeouts and retries configured.","Monitor storage health; close failures usually mirror connectivity problems seen elsewhere.","Keep Iceberg versions current — close-path bugs are fixed over time."],"tags":["io","resource-cleanup","unchecked-ioexception","delete-files"],"backgroundTag":"file-read-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}