apache/iceberg · error

Failed to delete file

Error message

Failed to delete file {}

What it means

ADLSFileIO.deleteFiles() bulk-deletes paths in parallel via Tasks; each per-file failure increments a counter and is logged at WARN. If any deletion failed, a BulkDeletionFailureException carrying the failure count is thrown after the batch completes.

Solutions

  1. Inspect the per-file WARN logs to identify failing paths
  2. Grant the identity delete permission (Storage Blob Data Contributor) on the container
  3. Retry the operation — already-deleted files may succeed or be tolerated depending on caller
  4. Reduce parallelism if ADLS throttling causes failures
Defensive patterns

Strategy: retry

Validate before calling

for (String p : paths) {
  // validate paths and permissions before bulk delete
  Preconditions.checkArgument(p.startsWith(location), "Path outside table location: %s", p);
}

Try / catch

try {
  io.deleteFiles(paths);
} catch (BulkDeletionFailureException e) {
  LOG.warn("{} files failed to delete; inspect WARN logs and retry", e.failedCount());
}

Prevention

When it happens

Trigger: Bulk deleting files where some paths are missing, permission-restricted, or hit transient ADLS errors; partial failures mixed with successes.

Common situations: Expiring snapshots whose some manifests were already removed; role changes mid-operation; throttling from ADLS during large cleanup batches.

Related errors


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

Appendix: source

Thrown at azure/src/main/java/org/apache/iceberg/azure/adlsv2/ADLSFileIO.java:206

      LOG.warn(
          "Unable to load metrics class: '{}', falling back to null metrics", DEFAULT_METRICS_IMPL);
    }
  }

  @Override
  public void deleteFiles(Iterable<String> pathsToDelete) throws BulkDeletionFailureException {
    // Azure batch operations are not supported in all cases, e.g. with a user
    // delegation SAS token, so avoid using it for now

    AtomicInteger failureCount = new AtomicInteger();
    Tasks.foreach(pathsToDelete)
        .executeWith(ThreadPools.getWorkerPool())
        .noRetry()
        .suppressFailureWhenFinished()
        .onFailure(
            (file, exc) -> {
              failureCount.incrementAndGet();
              LOG.warn("Failed to delete file {}", file, exc);
            })
        .run(this::deleteFile);

    if (failureCount.get() > 0) {
      throw new BulkDeletionFailureException(failureCount.get());
    }
  }

  @Override
  public Iterable<FileInfo> listPrefix(String prefix) {
    ADLSLocation location = new ADLSLocation(prefix);

    ListPathsOptions options = new ListPathsOptions();
    options.setPath(location.path());
    options.setRecursive(true);

    return () -> {
      try {

View on GitHub (pinned to 86d9c8fc54)