{"record":{"id":"e6432acc2fd00d86","repo":"apache/iceberg","slug":"failed-to-close-manifest-list-s","errorCode":null,"errorMessage":"Failed to close manifest list: %s","messagePattern":"Failed to close manifest list: (.+?)","errorType":"exception","errorClass":"RuntimeIOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/IncrementalFileCleanup.java","lineNumber":157,"sourceCode":"                  // whether the snapshot that created the manifest was an ancestor of the table\n                  // state\n                  boolean isFromAncestor = ancestorIds.contains(snapshotId);\n                  // whether the changes in this snapshot have been picked into the current table\n                  // state\n                  boolean isPicked = pickedAncestorSnapshotIds.contains(snapshotId);\n                  // if the snapshot that wrote this manifest is no longer valid (has expired),\n                  // then delete its deleted files. note that this is only for expired snapshots\n                  // that are in the\n                  // current table state\n                  if (!fromValidSnapshots\n                      && (isFromAncestor || isPicked)\n                      && manifest.hasDeletedFiles()) {\n                    manifestsToScan.add(manifest.copy());\n                  }\n                }\n\n              } catch (IOException e) {\n                throw new RuntimeIOException(\n                    e, \"Failed to close manifest list: %s\", snapshot.manifestListLocation());\n              }\n            });\n\n    // find manifests to clean up that were only referenced by snapshots that have expired\n    Set<String> manifestListsToDelete = ConcurrentHashMap.newKeySet();\n    Set<String> manifestsToDelete = ConcurrentHashMap.newKeySet();\n    Set<ManifestFile> manifestsToRevert = ConcurrentHashMap.newKeySet();\n    Tasks.foreach(beforeExpiration.snapshots())\n        .retry(3)\n        .suppressFailureWhenFinished()\n        .executeWith(planExecutorService)\n        .onFailure(\n            (snapshot, exc) ->\n                LOG.warn(\n                    \"Failed on snapshot {} while reading manifest list: {}\",\n                    snapshot.snapshotId(),\n                    snapshot.manifestListLocation(),","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/IncrementalFileCleanup.java#L139-L175","documentation":"During expire/cleanup, IncrementalFileCleanup reads each snapshot's manifest list as a CloseableIterable; if closing that iterable raises an IOException (e.g. object-store I/O error while closing the reader), it is wrapped as RuntimeIOException with the snapshot's manifest list location. This is an I/O failure during resource cleanup while determining which files to delete.","triggerScenarios":"Running table.expireSnapshots() (or removeOrphanFiles-style cleanup paths using IncrementalFileCleanup.cleanFiles) where closing a snapshot's manifest-list reader throws IOException - typically S3/GCS/HDFS transient I/O errors or connection resets.","commonSituations":"Expired credentials or network hiccups against object storage during expiry; underlying filesystem unavailable; read-ahead streams closed abnormally on the storage layer.","solutions":["Retry the expiry job; the failure is typically transient storage I/O.","Verify FileIO credentials and connectivity to the manifest list location shown in the message.","Check the underlying storage service health (S3/GCS/HDFS NameNode) for errors during the job window.","If persistent, inspect the cause chain (RuntimeIOException.getCause) for the concrete IOException."],"exampleFix":"// before\ntable.expireSnapshots().olderThan(ts).execute(); // aborts on one bad close\n// after\ntry {\n  table.expireSnapshots().olderThan(ts).execute();\n} catch (RuntimeIOException e) {\n  LOG.warn(\"retrying expiry after I/O failure\", e);\n  table.expireSnapshots().olderThan(ts).execute(); // transient manifest-list close failure\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  table.expireSnapshots().olderThan(ts).execute();\n} catch (RuntimeIOException e) {\n  if (e.getCause() instanceof IOException) {\n    // transient manifest-list close failure; retry with backoff\n    retryWithBackoff(() -> table.expireSnapshots().olderThan(ts).execute());\n  } else {\n    throw e;\n  }\n}","preventionTips":["Ensure stable credentials and network for FileIO storage before long expiry jobs.","Serialize expiry jobs so they don't race each other on manifest lists.","Monitor object-store error rates during maintenance windows."],"tags":["io","manifest-list","cleanup","object-storage"],"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"}