apache/iceberg · error · UncheckedIOException

Failed to close manifest reader

Error message

Failed to close manifest reader

What it means

When SnapshotChanges caches data-file changes it reads all relevant data manifests and closes the combined CloseableIterable in a try-with-resources block. If closing (or iterating) the manifest reader throws an IOException, it is rethrown as an UncheckedIOException with message 'Failed to close manifest reader'. It signals an I/O problem reading manifest files from the underlying FileIO, not a data corruption of the snapshot itself.

Source

Thrown at core/src/main/java/org/apache/iceberg/SnapshotChanges.java:151

            manifest -> Objects.equals(manifest.snapshotId(), snapshot.snapshotId()));

    Iterable<CloseableIterable<Pair<ManifestEntry.Status, DataFile>>> manifestReadTasks =
        Iterables.transform(relevantDataManifests, this::readDataManifest);

    try (CloseableIterable<Pair<ManifestEntry.Status, DataFile>> changedDataFiles =
        iterate(manifestReadTasks)) {
      for (Pair<ManifestEntry.Status, DataFile> pair : changedDataFiles) {
        switch (pair.first()) {
          case ADDED:
            adds.add(pair.second());
            break;
          case DELETED:
            deletes.add(pair.second());
            break;
        }
      }
    } catch (IOException e) {
      throw new UncheckedIOException("Failed to close manifest reader", e);
    }

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

  private CloseableIterable<Pair<ManifestEntry.Status, DataFile>> readDataManifest(
      ManifestFile manifest) {
    CloseableIterable<ManifestEntry<DataFile>> entries =
        ManifestFiles.read(manifest, io, specsById).entries();

    CloseableIterable<ManifestEntry<DataFile>> relevant =
        CloseableIterable.filter(entries, e -> e.status() != ManifestEntry.Status.EXISTING);

    return CloseableIterable.transform(
        relevant,
        entry -> {
          if (entry.status() == ManifestEntry.Status.ADDED) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Inspect the wrapped IOException cause to identify the real I/O failure (missing file, permissions, network).
  2. Retry the read — manifest reads are non-mutating and safe to repeat after a transient failure.
  3. Verify the manifest files still exist and are readable via the table's FileIO (check concurrent expiration/deletion).
  4. Refresh table metadata and re-create the Snapshot/SnapshotChanges if the snapshot is stale or its files were removed.
Defensive patterns

Strategy: try-catch

Validate before calling

// verify manifests exist before reading changes
for (ManifestFile m : snapshot.dataManifests(io)) {
  if (Objects.equals(m.snapshotId(), snapshot.snapshotId())) {
    Preconditions.checkArgument(io.newInputFile(m.path()).exists(),
        "Missing manifest: %s", m.path());
  }
}

Try / catch

try {
  Iterable<DataFile> added = changes.addedDataFiles();
} catch (UncheckedIOException e) {
  if (e.getMessage().contains("Failed to close manifest reader")) {
    LOG.warn("Transient manifest I/O failure, retrying after refresh", e);
    table.refresh();
    changes = SnapshotChanges.Builder.buildFrom(table.currentSnapshot(), ...);
    added = changes.addedDataFiles();
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling SnapshotChanges.addedDataFiles() or removedDataFiles() (first access triggers cacheDataFileChanges) while the underlying file system fails — e.g. missing/unreadable manifest file, network/credential failure to object storage, or an IOException thrown during close of the manifest readers.

Common situations: Manifest files deleted or expired concurrently (e.g. expireSnapshots removing files still referenced by an in-flight read); transient S3/HDFS access failures; expired cloud credentials mid-read; container/file-system interruptions.

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