apache/iceberg · error · RuntimeIOException

Failed to close manifest entries: %s

Error message

Failed to close manifest entries: %s

What it means

manifestHasDeletedFiles scans manifest entries to decide whether the manifest may contain files matching a delete expression. If the CloseableIterable of entries throws IOException while being consumed or closed, it is wrapped in this RuntimeIOException naming the manifest. The scan planning for the delete operation aborts.

Source

Thrown at core/src/main/java/org/apache/iceberg/ManifestFilterManager.java:492

          ValidationException.check(
              allRowsMatch || isDelete, // ignore delete files where some records may not match the
              // expression
              "Cannot delete file where some, but not all, rows match filter %s: %s",
              this.deleteExpression,
              file.location());

          if (allRowsMatch) {
            if (failAnyDelete) {
              throw new DeleteException(reader.spec().partitionToPath(file.partition()));
            }

            // as soon as a deleted file is detected, stop scanning
            return true;
          }
        }
      }
    } catch (IOException e) {
      throw new RuntimeIOException(e, "Failed to close manifest entries: %s", manifest);
    }

    return false;
  }

  private boolean isDanglingDV(DeleteFile file) {
    return ContentFileUtil.isDV(file) && removedDataFilePaths.contains(file.referencedDataFile());
  }

  @SuppressWarnings({"CollectionUndefinedEquality", "checkstyle:CyclomaticComplexity"})
  private ManifestFile filterManifestWithDeletedFiles(
      PartitionAndMetricsEvaluator evaluator, ManifestFile manifest, ManifestReader<F> reader) {
    boolean isDelete = reader.isDeleteManifestReader();
    // when this point is reached, there is at least one file that will be deleted in the
    // manifest. produce a copy of the manifest with all deleted files removed.
    Set<F> deletedFiles = newFileSet();
    AtomicInteger duplicateDeleteCount = new AtomicInteger(0);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Verify the manifest file exists and is readable at its location
  2. Restore the manifest if it was deleted by external cleanup processes
  3. Check the wrapped cause for the precise storage error and fix permissions/connectivity
Defensive patterns

Strategy: try-catch

Validate before calling

if (!io.newInputFile(manifest.location()).exists()) {
  throw new IllegalStateException("Manifest missing before filter: " + manifest.location());
}

Try / catch

try {
  boolean hasDeletes = manifestHasDeletedFiles(manifest, ...);
} catch (RuntimeIOException e) {
  throw new IllegalStateException("Cannot read manifest entries: " + manifest.location() + "; check storage/permissions", e);
}

Prevention

When it happens

Trigger: Calling filterManifest (via MergingSnapshotProducer) on a manifest whose entries cannot be read — corrupt manifest data file, missing manifest object in storage, or IO error while streaming entries.

Common situations: Manifests deleted externally (e.g. manual cleanup or aggressive lifecycle rules) before commit; corrupt AVRO manifests; storage read errors mid-scan; permission changes removing read access to old manifests.

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