{"record":{"id":"5f0cc817c4bbfb63","repo":"apache/iceberg","slug":"failed-to-read-manifest-file-s-5f0cc8","errorCode":null,"errorMessage":"Failed to read manifest file: %s","messagePattern":"Failed to read manifest file: (.+?)","errorType":"exception","errorClass":"RuntimeIOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/IncrementalFileCleanup.java","lineNumber":309,"sourceCode":"        .executeWith(planExecutorService)\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              // the manifest has deletes, scan it to find files to delete\n              try (ManifestReader<?> reader = ManifestFiles.open(manifest, fileIO, specsById)) {\n                for (ManifestEntry<?> entry : reader.entries()) {\n                  // if the snapshot ID of the DELETE entry is no longer valid, the data can be\n                  // deleted\n                  if (entry.status() == ManifestEntry.Status.DELETED\n                      && !validIds.contains(entry.snapshotId())) {\n                    // use toString to ensure the path will not change (Utf8 is reused)\n                    filesToDelete.add(entry.file().location());\n                  }\n                }\n              } catch (IOException e) {\n                throw new RuntimeIOException(e, \"Failed to read manifest file: %s\", manifest);\n              }\n            });\n\n    Tasks.foreach(manifestsToRevert)\n        .retry(3)\n        .suppressFailureWhenFinished()\n        .executeWith(planExecutorService)\n        .onFailure(\n            (item, exc) ->\n                LOG.warn(\"Failed to get added files: this may cause orphaned data files\", exc))\n        .run(\n            manifest -> {\n              // the manifest has deletes, scan it to find files to delete\n              try (ManifestReader<?> reader = ManifestFiles.open(manifest, fileIO, specsById)) {\n                for (ManifestEntry<?> entry : reader.entries()) {\n                  // delete any ADDED file from manifests that were reverted\n                  if (entry.status() == ManifestEntry.Status.ADDED) {\n                    // use toString to ensure the path will not change (Utf8 is reused)","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/IncrementalFileCleanup.java#L291-L327","documentation":"findFilesToDelete reads each candidate manifest file and, if closing/reading the manifest reader raises IOException, wraps it as RuntimeIOException with the manifest path. This failure aborts the file-deletion computation because it cannot be determined which data files are still referenced, and deleting files on an incomplete answer would be unsafe.","triggerScenarios":"Running ExpireSnapshots (filesToDelete path) where a manifest file referenced by a remaining snapshot cannot be read or closed - missing/corrupted manifest, storage I/O error, or revoked access.","commonSituations":"Manifests deleted externally or by a bad earlier job; object-store outages during expiry; permission changes on the table location mid-job.","solutions":["Restore or re-read the missing/corrupted manifest; check whether the manifest at the path in the message exists.","Retry the expiry job if the cause was a transient storage error.","Verify FileIO credentials/permissions for the manifest path.","Never manually delete manifests; if metadata is corrupted, restore table metadata from a backup or use a rollback to a good metadata version."],"exampleFix":"// before\ntable.expireSnapshots().olderThan(ts).execute(); // fails: manifest unreadable\n// after\nManifestFile missing = findMissingManifest(table);\nif (missing != null) {\n  restoreFromMetadataBackup(table); // or roll back metadata before expiring\n}\ntable.expireSnapshots().olderThan(ts).execute();","handlingStrategy":"retry","validationCode":"// before expiring, ensure all referenced manifests are readable:\nfor (ManifestFile m : table.currentSnapshot().allManifests(table.io())) {\n  if (!table.io().exists(m.path())) throw new IllegalStateException(\"missing manifest: \" + m.path());\n}","typeGuard":null,"tryCatchPattern":"try {\n  table.expireSnapshots().olderThan(ts).execute();\n} catch (RuntimeIOException e) {\n  // manifest unreadable: check existence/corruption before retrying\n  investigateManifest(e.getMessage());\n}","preventionTips":["Never delete manifest files manually; only expire via Iceberg APIs.","Back up table metadata before expiry so corrupted metadata can be rolled back.","Verify FileIO access to all manifest paths for retained snapshots before running expiry."],"tags":["io","manifest","cleanup","file-read"],"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-14T16:17:12.679Z"}