{"record":{"id":"6a96e9117745c7e3","repo":"apache/iceberg","slug":"failed-to-close-equality-delete-source","errorCode":null,"errorMessage":"Failed to close equality delete source","messagePattern":"Failed to close equality delete source","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/deletes/Deletes.java","lineNumber":126,"sourceCode":"            if (deleted) {\n              counter.increment();\n            }\n\n            return !deleted;\n          }\n        };\n\n    return remainingRowsFilter.filter(rows);\n  }\n\n  public static StructLikeSet toEqualitySet(\n      CloseableIterable<StructLike> eqDeletes, Types.StructType eqType) {\n    try (CloseableIterable<StructLike> deletes = eqDeletes) {\n      StructLikeSet deleteSet = StructLikeSet.create(eqType);\n      Iterables.addAll(deleteSet, deletes);\n      return deleteSet;\n    } catch (IOException e) {\n      throw new UncheckedIOException(\"Failed to close equality delete source\", e);\n    }\n  }\n\n  public static <T extends StructLike> CharSequenceMap<PositionDeleteIndex> toPositionIndexes(\n      CloseableIterable<T> posDeletes) {\n    return toPositionIndexes(posDeletes, null /* unknown delete file */);\n  }\n\n  /**\n   * Builds a map of position delete indexes by path.\n   *\n   * <p>This method builds a position delete index for each referenced data file and does not filter\n   * deletes. This can be useful when the entire delete file content is needed (e.g. caching).\n   *\n   * @param posDeletes position deletes\n   * @param file the source delete file for the deletes\n   * @return the map of position delete indexes by path\n   */","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/deletes/Deletes.java#L108-L144","documentation":"Deletes.toEqualitySet materializes an equality-delete iterable into a StructLikeSet inside a try-with-resources block. If closing the underlying delete source (typically an open delete file) throws an IOException, the library rethrows it as an UncheckedIOException so callers of the scan/apply path don't have to handle checked exceptions. The deletes were likely read; the failure happens during resource cleanup.","triggerScenarios":"Calling Deletes.toEqualitySet with a CloseableIterable whose close() throws IOException - e.g. an Avro/Parquet delete-file reader whose underlying FileIO stream fails while closing after full iteration.","commonSituations":"Underlying file deleted or truncated by concurrent compaction while reading equality deletes; HDFS/S3 I/O errors during stream close; network interruption to object storage mid-read of delete files.","solutions":["Inspect the wrapped IOException cause for the real storage error (permissions, missing file, network) and fix the underlying FileIO issue","Check for concurrent table maintenance (rewrite/delete of the delete file) during the read and enable retry of the scan","Verify the FileIO implementation's close path and storage connectivity (S3/HDFS) health","Retry the query/scan; if transient storage errors persist, check cluster/network stability"],"exampleFix":"// before\nCloseableIterable<StructLike> eqDeletes = openDeleteFile();\nStructLikeSet set = Deletes.toEqualitySet(eqDeletes, eqType); // UncheckedIOException on close\n// after\ntry {\n  StructLikeSet set = Deletes.toEqualitySet(eqDeletes, eqType);\n} catch (UncheckedIOException e) {\n  LOG.error(\"Equality delete source close failed\", e.getCause());\n  throw new RuntimeException(\"Retry scan: delete file unreadable\", e.getCause());\n}","handlingStrategy":"try-catch","validationCode":"// Validate storage access before scan\ntry (CloseableIterable<StructLike> it = openEqualityDeletes(deleteFile)) {\n  // peek: iteration will fail early if unreadable\n  it.iterator().hasNext();\n}","typeGuard":null,"tryCatchPattern":"try {\n  StructLikeSet set = Deletes.toEqualitySet(eqDeletes, eqType);\n} catch (UncheckedIOException e) {\n  LOG.error(\"Equality delete close failed\", e.getCause());\n  throw new RetryableScanException(e.getCause());\n}","preventionTips":["Ensure delete files are not expired/rewritten while scans are running","Use storage with stable connectivity; configure retries in FileIO","Catch UncheckedIOException at scan boundaries and inspect getCause()","Test FileIO implementations under network-fault injection"],"tags":["io","unchecked-ioexception","resource-cleanup","deletes"],"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"}