apache/iceberg · warning
Delete failed for
Error message
Delete failed for {}: {} What it means
A logged warning emitted per-file by BaseSparkAction.deleteFiles when deleting data/manifest files with Tasks.foreach + suppressFailureWhenFinished and an onFailure handler. Each deletion failure (with its exception and file path/type) is recorded but does not abort the rest of the batch, so a few failed deletes leave orphan files behind while the action otherwise succeeds.
Solutions
- Re-run the action; failed deletes leave files that a subsequent DeleteOrphanFiles pass will pick up.
- Fix IAM/storage permissions so the credential used can delete objects under the table location.
- Check the chained exception per file: 404 means the file is already gone (safe to ignore); 403 is a permissions fix.
- Avoid running two delete/expire jobs concurrently on the same table.
- Enable retries or reduce concurrency on the delete executor to work around rate limiting.
Example fix
// before .deleteFunc.accept(path); // throws per-file, logged and suppressed // after // re-run deleteFiles/ExpireSnapshots after fixing permissions: // SparkActions.get(spark).deleteOrphanFiles().olderThan(ts).execute(); // picks up orphaned leftovers
Defensive patterns
Strategy: retry
Validate before calling
// ensure the job principal can delete under the table location before running actions // (pre-check with a harmless write/delete in a test prefix)
Try / catch
try { action.execute(); } catch (Exception e) { /* inspect per-file onFailure logs; re-run action */ } Prevention
- Grant delete permissions to the job's principal on table/data prefixes
- Never run overlapping delete/expire jobs on the same table
- Re-run maintenance actions to pick up files left behind by failures
- Treat 404 causes as benign (already deleted) and fix 403 causes
When it happens
Trigger: Running actions such as DeleteOrphanFiles, RewriteDataFiles, or ExpireSnapshots that invoke BaseSparkAction.deleteFiles, when deleteFunc.accept(path) throws for individual files — permission errors, concurrent deletion by another job, object-store 404s/403s, or transient S3 errors.
Common situations: ExpireSnapshots racing with a concurrent delete job; IAM policies lacking s3:DeleteObject on some prefixes; files already removed by an earlier run (double deletion); rate limiting on bulk object-store deletes.
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
- Failed to delete file
- Cannot create table as the namespace does not exist
- Cannot find source table
- Cannot find source table
- Cannot find source table
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/a3b90a2ed5c080ed.
Report an issue: GitHub.
Appendix: source
Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/actions/BaseSparkAction.java:255
* @param deleteFunc a delete func
* @param files an iterator of Spark rows of the structure (path: String, type: String)
* @return stats on which files were deleted
*/
protected DeleteSummary deleteFiles(
ExecutorService executorService, Consumer<String> deleteFunc, Iterator<FileInfo> files) {
DeleteSummary summary = new DeleteSummary();
Tasks.foreach(files)
.retry(DELETE_NUM_RETRIES)
.stopRetryOn(NotFoundException.class)
.suppressFailureWhenFinished()
.executeWith(executorService)
.onFailure(
(fileInfo, exc) -> {
String path = fileInfo.getPath();
String type = fileInfo.getType();
LOG.warn("Delete failed for {}: {}", type, path, exc);
})
.run(
fileInfo -> {
String path = fileInfo.getPath();
String type = fileInfo.getType();
deleteFunc.accept(path);
summary.deletedFile(path, type);
});
return summary;
}
protected DeleteSummary deleteFiles(SupportsBulkOperations io, Iterator<FileInfo> files) {
DeleteSummary summary = new DeleteSummary();
Iterator<List<FileInfo>> fileGroups = Iterators.partition(files, DELETE_GROUP_SIZE);
Tasks.foreach(fileGroups)
.suppressFailureWhenFinished()View on GitHub (pinned to 86d9c8fc54)