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
- Inspect the wrapped IOException for the underlying read/connection error.
- Retry the rewrite/merge job — transient network failures are the most common cause.
- Validate suspect manifests by re-reading them; replace/copy corrupted files if storage supports it.
- 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
- Enable partial progress in rewrite/compaction jobs
- Increase object-store client timeouts for large merges
- Detect and quarantine truncated manifest files
- Run merges with stable network connectivity
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
- Cannot read manifest list file: %s
- Cannot read manifest list file: %s
- Failed to create snapshot list writer for path: %s
- Failed to create manifest writer for path: %s
- Failed to read manifest: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/eb38f69bf0e25a18.
Report an issue: GitHub.