apache/iceberg · warning
Bulk deletion failed
Error message
Bulk deletion failed
What it means
FileCleanupStrategy.deleteFiles first attempts a bulk delete API (e.g. S3 deleteObjects) via Tasks; if that bulk call fails outright it logs 'Bulk deletion failed' at WARN. The failure is logged and swallowed so the cleanup/expire operation itself does not abort; un-deleted files may be left behind as orphans.
Source
Thrown at core/src/main/java/org/apache/iceberg/FileCleanupStrategy.java:119
.build();
} else {
return CloseableIterable.withNoopClose(snapshot.allManifests(fileIO));
}
}
protected void deleteFiles(Set<String> pathsToDelete, String fileType) {
if (deleteFunc == null && fileIO instanceof SupportsBulkOperations) {
try {
((SupportsBulkOperations) fileIO).deleteFiles(pathsToDelete);
} catch (BulkDeletionFailureException e) {
LOG.warn(
"Bulk deletion failed for {} of {} {} file(s)",
e.numberFailedObjects(),
pathsToDelete.size(),
fileType,
e);
} catch (RuntimeException e) {
LOG.warn("Bulk deletion failed", e);
}
} else {
Consumer<String> deleteFuncToUse = deleteFunc == null ? defaultDeleteFunc : deleteFunc;
Tasks.foreach(pathsToDelete)
.executeWith(deleteExecutorService)
.retry(3)
.stopRetryOn(NotFoundException.class)
.stopOnFailure()
.suppressFailureWhenFinished()
.onFailure(
(file, thrown) -> LOG.warn("Delete failed for {} file: {}", fileType, file, thrown))
.run(deleteFuncToUse::accept);
}
}
protected boolean hasAnyStatisticsFiles(TableMetadata tableMetadata) {
return !tableMetadata.statisticsFiles().isEmpty()View on GitHub (pinned to 86d9c8fc54)
Solutions
- Check the logged cause 'e' in the WARN stack trace to identify the underlying storage error (permissions, throttling, unsupported operation).
- Ensure the FileIO credentials/permissions allow bulk deletion of the given file type (manifests, data, manifests-lists).
- If the store throttles, reduce delete concurrency or batch size, or retry the expire operation — remaining files can be cleaned by a later run.
- If the FileIO does not support bulk delete, implement bulkDelete() or configure a FileIO that does, so the non-bulk fallback path is not needed.
Example fix
// before: custom FileIO without bulk delete support
public void deleteFiles(Iterable<String> paths) { throw new UnsupportedOperationException(); }
// after: implement bulk delete or return unimplemented so the fallback single-delete path is used
public void deleteFiles(Iterable<String> pathsToRemove) {
Tasks.foreach(pathsToRemove).suppressFailureWhenFinished().run(io::deleteFile);
} Defensive patterns
Strategy: retry
Validate before calling
// before running cleanup, verify delete permission on one sample path io.deleteFile(samplePath); // throws early if credentials are insufficient
Try / catch
try {
table.expireSnapshots().expireOlderThan(ts).execute();
} catch (RuntimeException e) {
LOG.warn("Expiration reported partial failures; will re-run for orphans", e);
} Prevention
- Grant bulk-delete permissions (e.g. s3:DeleteObjects) to the maintenance job's credentials.
- Implement bulkDelete() in custom FileIO implementations.
- Avoid overlapping expiration jobs; schedule a single maintenance job.
- Re-run expiration periodically to clean files missed by transient failures.
When it happens
Trigger: Table maintenance (expireSnapshots, deleteFiles/orphan cleanup) calls deleteFiles with enough paths to take the bulk-deletion path, and the bulk delete call throws (IOException, rate limiting, ObjectStore permission error, bulk-delete not supported by the FileIO). Also hit when a custom FileIO's bulk delete implementation is not implemented and throws RuntimeException.
Common situations: S3/GCS throttling or 503s during heavy expiration of many snapshots; IAM credentials lacking s3:DeleteObjects; a custom FileIO whose bulkDelete() throws UnsupportedOperationException.
Related errors
- Delete failed for {} file: {}
- Failed to close manifest list: %s
- Failed to read manifest file: %s
- An error occurred while aborting the stream
- Failed on snapshot {} while reading manifest list: {}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/489cc1140edcc353.
Report an issue: GitHub.