{"record":{"id":"819997d47953dd6d","repo":"apache/iceberg","slug":"failed-to-close-manifest-reader-819997","errorCode":null,"errorMessage":"Failed to close manifest reader","messagePattern":"Failed to close manifest reader","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/SnapshotChanges.java","lineNumber":151,"sourceCode":"            manifest -> Objects.equals(manifest.snapshotId(), snapshot.snapshotId()));\n\n    Iterable<CloseableIterable<Pair<ManifestEntry.Status, DataFile>>> manifestReadTasks =\n        Iterables.transform(relevantDataManifests, this::readDataManifest);\n\n    try (CloseableIterable<Pair<ManifestEntry.Status, DataFile>> changedDataFiles =\n        iterate(manifestReadTasks)) {\n      for (Pair<ManifestEntry.Status, DataFile> pair : changedDataFiles) {\n        switch (pair.first()) {\n          case ADDED:\n            adds.add(pair.second());\n            break;\n          case DELETED:\n            deletes.add(pair.second());\n            break;\n        }\n      }\n    } catch (IOException e) {\n      throw new UncheckedIOException(\"Failed to close manifest reader\", e);\n    }\n\n    this.addedDataFiles = adds.build();\n    this.removedDataFiles = deletes.build();\n  }\n\n  private CloseableIterable<Pair<ManifestEntry.Status, DataFile>> readDataManifest(\n      ManifestFile manifest) {\n    CloseableIterable<ManifestEntry<DataFile>> entries =\n        ManifestFiles.read(manifest, io, specsById).entries();\n\n    CloseableIterable<ManifestEntry<DataFile>> relevant =\n        CloseableIterable.filter(entries, e -> e.status() != ManifestEntry.Status.EXISTING);\n\n    return CloseableIterable.transform(\n        relevant,\n        entry -> {\n          if (entry.status() == ManifestEntry.Status.ADDED) {","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/SnapshotChanges.java#L133-L169","documentation":"When SnapshotChanges caches data-file changes it reads all relevant data manifests and closes the combined CloseableIterable in a try-with-resources block. If closing (or iterating) the manifest reader throws an IOException, it is rethrown as an UncheckedIOException with message 'Failed to close manifest reader'. It signals an I/O problem reading manifest files from the underlying FileIO, not a data corruption of the snapshot itself.","triggerScenarios":"Calling SnapshotChanges.addedDataFiles() or removedDataFiles() (first access triggers cacheDataFileChanges) while the underlying file system fails — e.g. missing/unreadable manifest file, network/credential failure to object storage, or an IOException thrown during close of the manifest readers.","commonSituations":"Manifest files deleted or expired concurrently (e.g. expireSnapshots removing files still referenced by an in-flight read); transient S3/HDFS access failures; expired cloud credentials mid-read; container/file-system interruptions.","solutions":["Inspect the wrapped IOException cause to identify the real I/O failure (missing file, permissions, network).","Retry the read — manifest reads are non-mutating and safe to repeat after a transient failure.","Verify the manifest files still exist and are readable via the table's FileIO (check concurrent expiration/deletion).","Refresh table metadata and re-create the Snapshot/SnapshotChanges if the snapshot is stale or its files were removed."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify manifests exist before reading changes\nfor (ManifestFile m : snapshot.dataManifests(io)) {\n  if (Objects.equals(m.snapshotId(), snapshot.snapshotId())) {\n    Preconditions.checkArgument(io.newInputFile(m.path()).exists(),\n        \"Missing manifest: %s\", m.path());\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  Iterable<DataFile> added = changes.addedDataFiles();\n} catch (UncheckedIOException e) {\n  if (e.getMessage().contains(\"Failed to close manifest reader\")) {\n    LOG.warn(\"Transient manifest I/O failure, retrying after refresh\", e);\n    table.refresh();\n    changes = SnapshotChanges.Builder.buildFrom(table.currentSnapshot(), ...);\n    added = changes.addedDataFiles();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Ensure snapshot expiration jobs don't delete manifests still being read by concurrent consumers.","Use retry/backoff around snapshot-diff reads when using flaky object storage.","Keep credentials/session tokens valid for the duration of metadata reads.","Refresh table metadata before reading changes from long-lived snapshot references."],"tags":["java","io","manifest","snapshot","fileio"],"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"}