{"record":{"id":"629ee8a9d9ab0a93","repo":"apache/iceberg","slug":"failed-to-delete-629ee8","errorCode":null,"errorMessage":"Failed to delete {} ({})","messagePattern":"Failed to delete (.+?) \\((.+?)\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkCleanupUtil.java","lineNumber":101,"sourceCode":"   * @param files a list of files to delete\n   */\n  public static void deleteFiles(String context, FileIO io, List<? extends ContentFile<?>> files) {\n    List<String> paths = Lists.transform(files, ContentFile::location);\n    if (io instanceof SupportsBulkOperations) {\n      CatalogUtil.deleteFiles(io, paths, \"\");\n    } else {\n      delete(context, io, paths);\n    }\n  }\n\n  private static void delete(String context, FileIO io, List<String> paths) {\n    AtomicInteger deletedFilesCount = new AtomicInteger(0);\n\n    Tasks.foreach(paths)\n        .executeWith(ThreadPools.getWorkerPool())\n        .stopRetryOn(NotFoundException.class)\n        .suppressFailureWhenFinished()\n        .onFailure((path, exc) -> LOG.warn(\"Failed to delete {} ({})\", path, context, exc))\n        .retry(DELETE_NUM_RETRIES)\n        .exponentialBackoff(\n            DELETE_MIN_RETRY_WAIT_MS,\n            DELETE_MAX_RETRY_WAIT_MS,\n            DELETE_TOTAL_RETRY_TIME_MS,\n            2 /* exponential */)\n        .run(\n            path -> {\n              io.deleteFile(path);\n              deletedFilesCount.incrementAndGet();\n            });\n\n    if (deletedFilesCount.get() < paths.size()) {\n      LOG.warn(\"Deleted only {} of {} file(s) ({})\", deletedFilesCount, paths.size(), context);\n    } else {\n      LOG.info(\"Deleted {} file(s) ({})\", paths.size(), context);\n    }\n  }","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkCleanupUtil.java#L83-L119","documentation":"SparkCleanupUtil deletes streaming-operation data files with retries; when a file cannot be deleted after retries (or fails repeatedly), it logs this warning with the path and cleanup context. Failures are suppressed so the main operation continues — leftover files may need manual cleanup.","triggerScenarios":"Task attempt cleanup (deleteFiles) where io.deleteFile throws for a path — e.g. transient S3 errors, permissions, or the file already removed (NotFoundException stops retries).","commonSituations":"Cloud storage throttling/rate limits, concurrent jobs deleting the same files, misconfigured credentials/permissions for the cleanup executor.","solutions":["Check the chained exception for the root cause (permissions, throttling, missing file)","If the file is already gone, the failure is benign — ignore or verify with the storage backend","Fix credentials/permissions for the FileIO used by the streaming job","Manually delete orphaned leftovers once the root cause is fixed"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// verify FileIO credentials/permissions before starting streaming jobs: io.deleteFile(existingTestPath)","typeGuard":null,"tryCatchPattern":"try { io.deleteFile(path); } catch (NotFoundException e) { /* benign: already deleted */ } catch (Exception e) { /* inspect cause: permissions, throttling */ }","preventionTips":["Grant the job's FileIO delete permissions on the warehouse location","Handle cloud storage throttling (increase retries/backoff)","Avoid concurrent expiration of files being cleaned up"],"tags":["spark","file-delete","cleanup","retry"],"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"}