apache/iceberg · error · RuntimeIOException

Failed to close

Error message

Failed to close

What it means

DeleteFileIndex.loadDeleteFiles reads manifest entries inside Tasks.foreach with a CloseableIterable; an IOException while closing/reading the iterable during parallel loading is wrapped in RuntimeIOException with message 'Failed to close'. The deletes index therefore fails to build.

Solutions

  1. Inspect the cause (e.getCause()) for the underlying IOException and fix storage access/credentials.
  2. Retry the scan; transient cloud storage errors often resolve.
  3. Ensure snapshot expiry is not racing with scans; stop expiry during active query windows.
  4. Verify delete manifests referenced by the snapshot still exist and are readable.

Example fix

// before
CloseableIterable<...> items = ...; // leaked, failure occurs on implicit close
// after
try (CloseableIterable<...> items = ...) {
  ... // ensure proper resource handling around manifest reads
}
Defensive patterns

Strategy: retry

Validate before calling

// before scanning, verify delete manifests are present
table.operations().current().currentSnapshot().dataManifests(table.io())
    .forEach(m -> Preconditions.check(table.io().newInputFile(m.path()).exists(), "missing " + m.path()));

Try / catch

try { CloseableIterable<DeleteFile> f = index.files(); } catch (RuntimeIOException e) {
  LOG.error("delete index load failed", e.getCause());
  throw e;
}

Prevention

When it happens

Trigger: Building a DeleteFileIndex (e.g. via files() during a scan) where reading or closing a delete-manifest stream throws IOException — storage outage, deleted/missing manifest, credentials revoked mid-scan.

Common situations: S3/GCS transient errors during large delete-index loads; concurrent snapshot expiration deleting manifests while a scan plans; misconfigured FileIO credentials.

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/bf6712c9f28762ca. Report an issue: GitHub.

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/DeleteFileIndex.java:516

          .throwFailureWhenFinished()
          .executeWith(executorService)
          .run(
              deleteFile -> {
                try (CloseableIterable<ManifestEntry<DeleteFile>> reader = deleteFile) {
                  for (ManifestEntry<DeleteFile> entry : reader) {
                    if (entry.dataSequenceNumber() > minSequenceNumber) {
                      DeleteFile file = entry.file();
                      // keep minimum stats to avoid memory pressure
                      Set<Integer> columns =
                          file.content() == FileContent.POSITION_DELETES
                              ? Set.of(MetadataColumns.DELETE_FILE_PATH.fieldId())
                              : Set.copyOf(file.equalityFieldIds());
                      // copy with stats for better filtering against data file stats
                      files.add(ContentFileUtil.copy(file, true, columns));
                    }
                  }
                } catch (IOException e) {
                  throw new RuntimeIOException(e, "Failed to close");
                }
              });
      return files;
    }

    private Collection<Schema> schemas() {
      if (schemasById != null) {
        return schemasById.values();
      } else {
        return specsById.values().stream().map(PartitionSpec::schema).collect(Collectors.toList());
      }
    }

    DeleteFileIndex build() {
      Map<Integer, Types.NestedField> fieldsById = Schema.indexFields(schemas());
      Function<Integer, Types.NestedField> fieldLookup = fieldsById::get;
      Iterable<DeleteFile> files = deleteFiles != null ? filterDeleteFiles() : loadDeleteFiles();

View on GitHub (pinned to 86d9c8fc54)