{"record":{"id":"41b8e9bfefc292ad","repo":"apache/iceberg","slug":"failed-to-delete-file-41b8e9","errorCode":null,"errorMessage":"Failed to delete file: {}","messagePattern":"Failed to delete file: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/actions/DeleteOrphanFilesSparkAction.java","lineNumber":336,"sourceCode":"\n  private void deleteBulk(SupportsBulkOperations io, List<String> paths) {\n    try {\n      io.deleteFiles(paths);\n      LOG.info(\"Deleted {} files using bulk deletes\", paths.size());\n    } catch (BulkDeletionFailureException e) {\n      int deletedFilesCount = paths.size() - e.numberFailedObjects();\n      LOG.warn(\n          \"Deleted only {} of {} files using bulk deletes\", deletedFilesCount, paths.size(), e);\n    }\n  }\n\n  private void deleteNonBulk(List<String> paths) {\n    Tasks.Builder<String> deleteTasks =\n        Tasks.foreach(paths)\n            .noRetry()\n            .executeWith(deleteExecutorService)\n            .suppressFailureWhenFinished()\n            .onFailure((file, exc) -> LOG.warn(\"Failed to delete file: {}\", file, exc));\n\n    if (deleteFunc == null) {\n      LOG.info(\n          \"Table IO {} does not support bulk operations. Using non-bulk deletes.\",\n          table.io().getClass().getName());\n      deleteTasks.run(table.io()::deleteFile);\n    } else {\n      LOG.info(\"Custom delete function provided. Using non-bulk deletes\");\n      deleteTasks.run(deleteFunc::accept);\n    }\n  }\n\n  @VisibleForTesting\n  static Dataset<String> findOrphanFiles(\n      Dataset<FileURI> actualFileIdentDS,\n      Dataset<FileURI> validFileIdentDS,\n      PrefixMismatchMode prefixMismatchMode) {\n","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/actions/DeleteOrphanFilesSparkAction.java#L318-L354","documentation":"When the table's FileIO does not implement SupportsBulkOperations, DeleteOrphanFiles falls back to deleting files one-by-one with Tasks.foreach. Each individual failure is logged with this warning (file path plus exception) and suppressed so the overall cleanup continues.","triggerScenarios":"Running DeleteOrphanFiles with a non-bulk FileIO (e.g. HadoopFileIO) where individual io.deleteFile calls fail — permission denied, file already gone, or transient filesystem errors.","commonSituations":"HDFS permission errors after permission model changes; files deleted concurrently by another GC run; NFS/S3A transient IOExceptions under load.","solutions":["Re-run DeleteOrphanFiles after fixing the underlying cause; already-cleaned files are simply skipped.","Grant the job's principal delete permission on the table location (HDFS ACLs or cloud IAM).","Switch to a FileIO with bulk support (S3FileIO) for better throughput and consolidated error reporting.","If failures cluster on one prefix, check lifecycle rules or concurrent processes competing to delete the same files."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm delete permission before cleanup\nio.deleteFile(testPath);","typeGuard":"if (!(table.io() instanceof SupportsBulkOperations)) { /* non-bulk path: expect per-file failures */ }","tryCatchPattern":null,"preventionTips":["Fix HDFS/cloud IAM delete permissions for the job principal.","Prefer a bulk-capable FileIO (e.g. S3FileIO) for large cleanups.","Run cleanup regularly so failures surface in small batches.","Avoid concurrent GC jobs competing for the same files."],"tags":["spark","orphan-file-cleanup","file-deletion"],"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-14T16:17:12.679Z"}