apache/iceberg · warning

Deleted only {} of {} files using bulk deletes

Error message

Deleted only {} of {} files using bulk deletes

What it means

DeleteOrphanFilesSparkAction uses the FileIO's bulk delete API when supported. If the object store reports that some objects in the bulk request failed (BulkDeletionFailureException carries the failed count), the action logs this warning with how many of the total paths were actually deleted rather than throwing.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/actions/DeleteOrphanFilesSparkAction.java:325

  }

  private void collectPathsForOutput(
      List<String> paths, List<String> orphanFileList, int maxSampleSize) {
    if (streamResults()) {
      int lengthToAdd = Math.min(maxSampleSize - orphanFileList.size(), paths.size());
      orphanFileList.addAll(paths.subList(0, lengthToAdd));
    } else {
      orphanFileList.addAll(paths);
    }
  }

  private void deleteBulk(SupportsBulkOperations io, List<String> paths) {
    try {
      io.deleteFiles(paths);
      LOG.info("Deleted {} files using bulk deletes", paths.size());
    } catch (BulkDeletionFailureException e) {
      int deletedFilesCount = paths.size() - e.numberFailedObjects();
      LOG.warn(
          "Deleted only {} of {} files using bulk deletes", deletedFilesCount, paths.size(), e);
    }
  }

  private void deleteNonBulk(List<String> paths) {
    Tasks.Builder<String> deleteTasks =
        Tasks.foreach(paths)
            .noRetry()
            .executeWith(deleteExecutorService)
            .suppressFailureWhenFinished()
            .onFailure((file, exc) -> LOG.warn("Failed to delete file: {}", file, exc));

    if (deleteFunc == null) {
      LOG.info(
          "Table IO {} does not support bulk operations. Using non-bulk deletes.",
          table.io().getClass().getName());
      deleteTasks.run(table.io()::deleteFile);
    } else {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Re-run the DeleteOrphanFiles action — remaining older-than-threshold files will be retried.
  2. Lower the batch size / concurrency of the S3FileIO if throttling causes partial failures.
  3. Check bucket retention/Object Lock and versioning settings for objects that permanently refuse deletion.
  4. If guaranteed cleanup is required, force the non-bulk path by using a FileIO without bulk support or by deleting the reported paths individually.
Defensive patterns

Strategy: retry

Validate before calling

if (table.io() instanceof SupportsBulkOperations) { /* bulk path: expect partial failures */ }

Type guard

if (table.io() instanceof SupportsBulkOperations bulkIo) { bulkIo.deleteFiles(paths); }

Prevention

When it happens

Trigger: Calling DeleteOrphanFiles (RemoveOrphanFiles) against a FileIO implementing SupportsBulkOperations (e.g. S3FileIO) where io.deleteFiles(paths) partially fails, raising BulkDeletionFailureException with numberFailedObjects > 0.

Common situations: S3 multi-object delete partial failures; objects locked by retention policies (Object Lock) that cannot be removed; transient object-store errors during large bulk batches.

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