apache/iceberg · error · RuntimeIOException

Failed to close manifest reader

Error message

Failed to close manifest reader

What it means

Raised when closing the Avro manifest reader during manifest merge fails with an IOException. ManifestMergeManager.createManifest merges entries from older manifests into a new one and closes each source reader; a close failure is wrapped as RuntimeIOException.

Source

Thrown at core/src/main/java/org/apache/iceberg/ManifestMergeManager.java:218

            manifest.snapshotId() != null && snapshotId() != manifest.snapshotId();
        try (ManifestReader<F> reader = newManifestReader(manifest, isCommitted)) {
          for (ManifestEntry<F> entry : reader.entries()) {
            if (entry.status() == Status.DELETED) {
              // suppress deletes from previous snapshots. only files deleted by this snapshot
              // should be added to the new manifest
              if (entry.snapshotId() == snapshotId()) {
                writer.delete(entry);
              }
            } else if (entry.status() == Status.ADDED && entry.snapshotId() == snapshotId()) {
              // adds from this snapshot are still adds, otherwise they should be existing
              writer.add(entry);
            } else {
              // add all files from the old manifest as existing files
              writer.existing(entry);
            }
          }
        } catch (IOException e) {
          throw new RuntimeIOException(e, "Failed to close manifest reader");
        }
      }
      threw = false;

    } finally {
      Exceptions.close(writer, threw);
    }

    ManifestFile manifest = writer.toManifestFile();

    // cache the merged manifest to reuse when retrying and track replaced manifests
    mergedManifests.put(bin, manifest);
    for (ManifestFile m : bin) {
      // only count manifests from previous snapshots; in-memory manifests are not replaced
      if (snapshotId() != m.snapshotId()) {
        replacedManifestsCount.incrementAndGet();
      }
    }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Inspect the wrapped IOException for the underlying read/connection error.
  2. Retry the rewrite/merge job — transient network failures are the most common cause.
  3. Validate suspect manifests by re-reading them; replace/copy corrupted files if storage supports it.
  4. Ensure executor network stability / increase object store client timeouts.

Example fix

// before: single-shot rewrite susceptible to transient IO errors
SparkActions.get().rewriteDataFiles(table).execute();
// after: enable retry/partial progress in the action
SparkActions.get().rewriteDataFiles(table)
    .option("max-concurrent-file-group-rewrites", "4")
    .option("partial-progress.enabled", "true")
    .execute();
Defensive patterns

Strategy: retry

Validate before calling

// validate manifests readable before merge
for (ManifestFile m : manifestsToMerge) {
  try (ManifestReader<?> r = ManifestFiles.read(m, io)) {
    r.iterator().hasNext(); // force open
  }
}

Try / catch

try {
  mergeOperation.commit();
} catch (RuntimeIOException e) {
  if (isTransientNetwork(e.getCause())) retryWithBackoff();
  else throw new IllegalStateException("Corrupt manifest: " + e.getCause());
}

Prevention

When it happens

Trigger: During mergeGroup/createManifest, iterating the source ManifestReader throws IOException on close — typically an underlying stream read/flush error surfaced at close time (truncated file, network drop, object-store error while draining the Avro stream).

Common situations: Object store connection reset mid-read during large compaction/rewrite jobs in Spark executors; corrupted or truncated manifest files left by a failed previous write; ephemeral network partitions during long-running merge tasks.

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