{"record":{"id":"a3b90a2ed5c080ed","repo":"apache/iceberg","slug":"delete-failed-for-a3b90a","errorCode":null,"errorMessage":"Delete failed for {}: {}","messagePattern":"Delete failed for (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/actions/BaseSparkAction.java","lineNumber":255,"sourceCode":"   * @param deleteFunc a delete func\n   * @param files an iterator of Spark rows of the structure (path: String, type: String)\n   * @return stats on which files were deleted\n   */\n  protected DeleteSummary deleteFiles(\n      ExecutorService executorService, Consumer<String> deleteFunc, Iterator<FileInfo> files) {\n\n    DeleteSummary summary = new DeleteSummary();\n\n    Tasks.foreach(files)\n        .retry(DELETE_NUM_RETRIES)\n        .stopRetryOn(NotFoundException.class)\n        .suppressFailureWhenFinished()\n        .executeWith(executorService)\n        .onFailure(\n            (fileInfo, exc) -> {\n              String path = fileInfo.getPath();\n              String type = fileInfo.getType();\n              LOG.warn(\"Delete failed for {}: {}\", type, path, exc);\n            })\n        .run(\n            fileInfo -> {\n              String path = fileInfo.getPath();\n              String type = fileInfo.getType();\n              deleteFunc.accept(path);\n              summary.deletedFile(path, type);\n            });\n\n    return summary;\n  }\n\n  protected DeleteSummary deleteFiles(SupportsBulkOperations io, Iterator<FileInfo> files) {\n    DeleteSummary summary = new DeleteSummary();\n    Iterator<List<FileInfo>> fileGroups = Iterators.partition(files, DELETE_GROUP_SIZE);\n\n    Tasks.foreach(fileGroups)\n        .suppressFailureWhenFinished()","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/actions/BaseSparkAction.java#L237-L273","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n.deleteFunc.accept(path);  // throws per-file, logged and suppressed\n// after\n// re-run deleteFiles/ExpireSnapshots after fixing permissions:\n// SparkActions.get(spark).deleteOrphanFiles().olderThan(ts).execute();  // picks up orphaned leftovers","handlingStrategy":"retry","validationCode":"// ensure the job principal can delete under the table location before running actions\n// (pre-check with a harmless write/delete in a test prefix)","typeGuard":null,"tryCatchPattern":"try { action.execute(); } catch (Exception e) { /* inspect per-file onFailure logs; re-run action */ }","preventionTips":["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"],"tags":["spark","actions","file-deletion","io"],"backgroundTag":"file-write-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}