apache/iceberg · error · RuntimeIOException

Failed to close entries while caching changes

Error message

Failed to close entries while caching changes

What it means

A sibling of the reader-close failure on the data path: while caching data-file changes, closing the ManifestReader after iteration throws an IOException, which Iceberg converts to RuntimeIOException with message "Failed to close entries while caching changes".

Solutions

  1. Retry the call after table.refresh(); typically transient
  2. Ensure credentials/Tokens are valid for the duration of the scan (refresh STS tokens, session tokens)
  3. Prevent expireSnapshots/orphan cleanup from racing with incremental change readers
  4. Check storage backend health and network stability

Example fix

// before
List<DataFile> added = snapshot.addedDataFiles();
// after
try {
  List<DataFile> added = snapshot.addedDataFiles();
} catch (RuntimeIOException e) {
  table.refresh();
  List<DataFile> added = snapshot.addedDataFiles();
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure credentials valid for scan duration
if (credentialsExpiryEpochMs < System.currentTimeMillis() + scanDurationMs) refreshCredentials();

Try / catch

try { snapshot.addedDataFiles(); } catch (RuntimeIOException e) { table.refresh(); retryWithBackoff(); }

Prevention

When it happens

Trigger: Calling addedDataFiles()/removedDataFiles() when the underlying object store fails while closing the manifest reader: connection reset, credentials expiring mid-scan, or the manifest being deleted concurrently.

Common situations: Long-running incremental-scan jobs whose cloud credentials expire; S3/GCS throttling; cleanup jobs removing manifests mid-read.

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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/BaseSnapshot.java:324

        Iterables.filter(
            dataManifests(fileIO), manifest -> Objects.equal(manifest.snapshotId(), snapshotId));
    try (CloseableIterable<ManifestEntry<DataFile>> entries =
        new ManifestGroup(fileIO, changedManifests).ignoreExisting().entries()) {
      for (ManifestEntry<DataFile> entry : entries) {
        switch (entry.status()) {
          case ADDED:
            adds.add(entry.file().copy());
            break;
          case DELETED:
            deletes.add(entry.file().copyWithoutStats());
            break;
          default:
            throw new IllegalStateException(
                "Unexpected entry status, not added or deleted: " + entry);
        }
      }
    } catch (IOException e) {
      throw new RuntimeIOException(e, "Failed to close entries while caching changes");
    }

    this.addedDataFiles = adds.build();
    this.removedDataFiles = deletes.build();
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }

    if (o instanceof BaseSnapshot) {
      BaseSnapshot other = (BaseSnapshot) o;
      return this.snapshotId == other.snapshotId()
          && Objects.equal(this.parentId, other.parentId())
          && this.sequenceNumber == other.sequenceNumber()
          && this.timestampMillis == other.timestampMillis()

View on GitHub (pinned to 86d9c8fc54)