apache/iceberg · error · RuntimeIOException

Failed to close manifest list: %s

Error message

Failed to close manifest list: %s

What it means

During expire/cleanup, IncrementalFileCleanup reads each snapshot's manifest list as a CloseableIterable; if closing that iterable raises an IOException (e.g. object-store I/O error while closing the reader), it is wrapped as RuntimeIOException with the snapshot's manifest list location. This is an I/O failure during resource cleanup while determining which files to delete.

Source

Thrown at core/src/main/java/org/apache/iceberg/IncrementalFileCleanup.java:157

                  // whether the snapshot that created the manifest was an ancestor of the table
                  // state
                  boolean isFromAncestor = ancestorIds.contains(snapshotId);
                  // whether the changes in this snapshot have been picked into the current table
                  // state
                  boolean isPicked = pickedAncestorSnapshotIds.contains(snapshotId);
                  // if the snapshot that wrote this manifest is no longer valid (has expired),
                  // then delete its deleted files. note that this is only for expired snapshots
                  // that are in the
                  // current table state
                  if (!fromValidSnapshots
                      && (isFromAncestor || isPicked)
                      && manifest.hasDeletedFiles()) {
                    manifestsToScan.add(manifest.copy());
                  }
                }

              } catch (IOException e) {
                throw new RuntimeIOException(
                    e, "Failed to close manifest list: %s", snapshot.manifestListLocation());
              }
            });

    // find manifests to clean up that were only referenced by snapshots that have expired
    Set<String> manifestListsToDelete = ConcurrentHashMap.newKeySet();
    Set<String> manifestsToDelete = ConcurrentHashMap.newKeySet();
    Set<ManifestFile> manifestsToRevert = ConcurrentHashMap.newKeySet();
    Tasks.foreach(beforeExpiration.snapshots())
        .retry(3)
        .suppressFailureWhenFinished()
        .executeWith(planExecutorService)
        .onFailure(
            (snapshot, exc) ->
                LOG.warn(
                    "Failed on snapshot {} while reading manifest list: {}",
                    snapshot.snapshotId(),
                    snapshot.manifestListLocation(),

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Retry the expiry job; the failure is typically transient storage I/O.
  2. Verify FileIO credentials and connectivity to the manifest list location shown in the message.
  3. Check the underlying storage service health (S3/GCS/HDFS NameNode) for errors during the job window.
  4. If persistent, inspect the cause chain (RuntimeIOException.getCause) for the concrete IOException.

Example fix

// before
table.expireSnapshots().olderThan(ts).execute(); // aborts on one bad close
// after
try {
  table.expireSnapshots().olderThan(ts).execute();
} catch (RuntimeIOException e) {
  LOG.warn("retrying expiry after I/O failure", e);
  table.expireSnapshots().olderThan(ts).execute(); // transient manifest-list close failure
}
Defensive patterns

Strategy: retry

Try / catch

try {
  table.expireSnapshots().olderThan(ts).execute();
} catch (RuntimeIOException e) {
  if (e.getCause() instanceof IOException) {
    // transient manifest-list close failure; retry with backoff
    retryWithBackoff(() -> table.expireSnapshots().olderThan(ts).execute());
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Running table.expireSnapshots() (or removeOrphanFiles-style cleanup paths using IncrementalFileCleanup.cleanFiles) where closing a snapshot's manifest-list reader throws IOException - typically S3/GCS/HDFS transient I/O errors or connection resets.

Common situations: Expired credentials or network hiccups against object storage during expiry; underlying filesystem unavailable; read-ahead streams closed abnormally on the storage layer.

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