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

  1. Resolve the underlying storage error from the exception cause
  2. Retry the delete operation — it is safe to retry since no snapshot was committed
  3. 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

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


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/ae6b2662c674764a. Report an issue: GitHub.