{"record":{"id":"07d70234a09a53d6","repo":"apache/iceberg","slug":"failed-to-get-deleted-files-this-may-cause-orphan","errorCode":null,"errorMessage":"Failed to get deleted files: this may cause orphaned data files","messagePattern":"Failed to get deleted files: this may cause orphaned data files","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/src/main/java/org/apache/iceberg/CatalogUtil.java","lineNumber":178,"sourceCode":"    if (gcEnabled) {\n      deleteFile(io, metadata.metadataFileLocation(), \"metadata\");\n    }\n  }\n\n  @SuppressWarnings(\"DangerousStringInternUsage\")\n  private static void deleteFiles(\n      FileIO io, Set<ManifestFile> allManifests, Map<Integer, PartitionSpec> specsById) {\n    // keep track of deleted files in a map that can be cleaned up when memory runs low\n    Map<String, Boolean> deletedFiles =\n        new MapMaker().concurrencyLevel(ThreadPools.WORKER_THREAD_POOL_SIZE).weakKeys().makeMap();\n\n    Tasks.foreach(allManifests)\n        .noRetry()\n        .suppressFailureWhenFinished()\n        .executeWith(ThreadPools.getWorkerPool())\n        .onFailure(\n            (item, exc) ->\n                LOG.warn(\"Failed to get deleted files: this may cause orphaned data files\", exc))\n        .run(\n            manifest -> {\n              try (ManifestReader<?> reader = ManifestFiles.open(manifest, io, specsById)) {\n                List<String> pathsToDelete = Lists.newArrayList();\n                for (ManifestEntry<?> entry : reader.entries()) {\n                  // intern the file path because the weak key map uses identity (==) instead of\n                  // equals\n                  String path = entry.file().location().intern();\n                  Boolean alreadyDeleted = deletedFiles.putIfAbsent(path, true);\n                  if (alreadyDeleted == null || !alreadyDeleted) {\n                    pathsToDelete.add(path);\n                  }\n                }\n\n                String type = reader.isDeleteManifestReader() ? \"delete\" : \"data\";\n                deleteFiles(io, pathsToDelete, type, false);\n              } catch (IOException e) {\n                throw new RuntimeIOException(","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/CatalogUtil.java#L160-L196","documentation":"A WARN logged via Tasks' onFailure callback while CatalogUtil.deleteFiles scans manifests in parallel to collect files that are safe to delete after a table drop. If reading a manifest fails, the set of deleted files is incomplete — files referenced by the failed manifest will NOT be deleted, resulting in orphaned data/manifest files. The drop itself still proceeds; this warning signals storage leak, not data loss for surviving tables.","triggerScenarios":"dropTableData or deleteRemovedMetadataFiles triggers parallel manifest reads; a manifest file is unreadable — deleted/corrupted in object storage, missing permissions, missing spec entry (specsById mismatch), or transient S3/GCS errors.","commonSituations":"Table partially corrupted by a prior failed cleanup; IAM/permission changes between metadata read and manifest read; lifecycle policies deleting manifest files early; cross-region storage issues.","solutions":["Re-run the drop with the table's metadata intact, or manually list and delete the files referenced by the failed manifests.","Fix storage permissions (FileIO credentials) so all manifests under the metadata location are readable.","Check object-store lifecycle rules so manifests are not deleted before the table is dropped.","Use the platform's orphan-file cleanup (e.g. Spark deleteOrphanFiles) to remove the leaked files."],"exampleFix":"// before: drop fails silently leaving orphans\ncatalog.dropTable(identifier);\n// after: sweep orphans afterwards\nif (!catalog.tableExists(identifier)) {\n  SparkActions.get().deleteOrphanFiles(spark, \"s3://bucket/db/tbl\").execute();\n}","handlingStrategy":"fallback","validationCode":"// ensure manifests readable before drop\nallManifests.forEach(m -> ManifestFiles.read(m, io).close());","typeGuard":null,"tryCatchPattern":"try { catalog.dropTable(identifier); } finally { scheduleOrphanFileSweep(tableLocation); }","preventionTips":["Run deleteOrphanFiles after drops to catch leaked files","Keep manifest files under the table location (not external paths)","Avoid lifecycle rules that delete files before the table is dropped","Grant delete/read permissions uniformly on the table prefix"],"tags":["manifest","io","orphan-files"],"backgroundTag":"file-read-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}