apache/iceberg · error · RuntimeIOException
Failed to close manifest: %s
Error message
Failed to close manifest: %s
What it means
ManifestFilterManager.filterManifest builds a filtered manifest for a delete/cleanup operation and closes the manifest writer in a try/catch. If an IOException occurs during writer finalization (or iterating entries), it is rethrown as RuntimeIOException naming the source manifest. The delete operation cannot produce its filtered manifest.
Source
Thrown at core/src/main/java/org/apache/iceberg/ManifestFilterManager.java:397
}
try (ManifestReader<F> reader = newManifestReader(manifest)) {
PartitionSpec spec = reader.spec();
PartitionAndMetricsEvaluator evaluator =
new PartitionAndMetricsEvaluator(tableSchema, spec, deleteExpression);
// this assumes that the manifest doesn't have files to remove and streams through the
// manifest without copying data. if a manifest does have a file to remove, this will break
// out of the loop and move on to filtering the manifest.
if (manifestHasDeletedFiles(evaluator, manifest, reader)) {
ManifestFile filtered = filterManifestWithDeletedFiles(evaluator, manifest, reader);
replacedManifestsCount.incrementAndGet();
return filtered;
} else {
filteredManifests.put(manifest, manifest);
return manifest;
}
} catch (IOException e) {
throw new RuntimeIOException(e, "Failed to close manifest: %s", manifest);
}
}
private boolean canContainDeletedFiles(ManifestFile manifest, boolean trustManifestReferences) {
if (hasNoLiveFiles(manifest)) {
return false;
}
if (trustManifestReferences) {
return manifestsWithDeletes.contains(manifest.path());
}
return canContainDroppedFiles(manifest)
|| canContainExpressionDeletes(manifest)
|| canContainDroppedPartitions(manifest);
}
private boolean hasNoLiveFiles(ManifestFile manifest) {View on GitHub (pinned to 86d9c8fc54)
Solutions
- Resolve the underlying storage error from the exception cause
- Retry the delete operation — it is safe to retry since no snapshot was committed
- Check FileIO permissions and quota for the table's manifest location
Defensive patterns
Strategy: try-catch
Validate before calling
// confirm all manifests referenced by the snapshot are readable
for (ManifestFile m : snapshot.allManifests(table.io())) {
Preconditions.checkArgument(table.io().newInputFile(m.location()).exists(), "Missing manifest: %s", m.location());
} Try / catch
try {
table.deleteFiles()/* or other MergingSnapshotProducer op */;
} catch (RuntimeIOException e) {
LOG.error("Manifest finalization failed for {}; safe to retry", e.getMessage(), e);
throw e;
} Prevention
- Do not delete manifest files out-of-band; rely on expireSnapshots
- Ensure long delete operations use renewable credentials
- Retry failed deletes — no snapshot is committed on failure
When it happens
Trigger: Calling MergingSnapshotProducer operations (deleteFiles, RowLevel operations, expire) where filterManifest's writer close fails due to storage errors while writing the filtered manifest for a partition.
Common situations: Object storage transient failures during snapshot commit; credentials expiring during large delete operations; disk/quota exhaustion; network instability to the warehouse.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to close manifest writer
- Failed to write manifest
- Failed to close manifest: %s
- Failed to close manifest entries: %s
- Failed to close current writer
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/ae6b2662c674764a.
Report an issue: GitHub.