apache/iceberg · error · IllegalArgumentException
Cannot cache changes: FileIO is null
Error message
Cannot cache changes: FileIO is null
What it means
BaseSnapshot.cacheManifests needs a FileIO to load manifest files from their locations, but was handed a null FileIO. Snapshots obtained without an initialized table IO (e.g. from deserialization or a raw TableMetadata) cannot lazily load manifests, so an IllegalArgumentException is thrown.
Solutions
- Load manifests through a fully initialized Table (catalog.loadTable) so io() is non-null before calling dataManifests()
- Pass the table's FileIO explicitly via the snapshot API overloads (dataManifests(fileIO)) where available
- If working from TableMetadata, build the snapshot with table.io() instead of the no-IO constructor
- Ensure SerializableTable/serialized table state keeps a non-null FileIO supplier
Example fix
// before Snapshot snap = table.operations().current().snapshots()[0]; List<ManifestFile> m = snap.dataManifests(null).stream()...; // no IO // after List<ManifestFile> m = snap.dataManifests(table.io()).stream()...;
Defensive patterns
Strategy: type-guard
Validate before calling
if (table.io() == null) throw new IllegalStateException("table FileIO not initialized; load via catalog.loadTable"); Type guard
boolean hasIO(Snapshot s, FileIO io) { return io != null && s != null; } Try / catch
try { snapshot.dataManifests(table.io()); } catch (IllegalArgumentException e) { throw new IllegalStateException("use an IO-backed snapshot", e); } Prevention
- Always access snapshots through a catalog-loaded Table so io() is set
- Use dataManifests(fileIO) overloads with the table's IO when constructing snapshots manually
- Keep FileIO in SerializableTable suppliers when shipping tables to executors
When it happens
Trigger: Calling snapshot.dataManifests()/deleteManifests()/allManifests() on a Snapshot that was constructed without a FileIO — e.g. a snapshot obtained from TableMetadata directly, a deserialized snapshot, or a table whose io() was never initialized (lazy table loading).
Common situations: Reading snapshots in a custom catalog that did not wire the FileIO; using snapshot objects recovered from serialized job state; accessing manifests from a MetadataTable or test harness that built snapshots manually.
Related errors
- ALTER VIEW AS is not supported. Use CREATE OR REPLACE VIEW…
- apply(value) is deprecated, use bind(Type).apply(value)
- apply(value) is deprecated, use bind(Type).apply(value)
- AS OF is not supported for changelogs
- bind is not implemented
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/81d9a3fac9e3d4f9.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/BaseSnapshot.java:171
@Override
public Long firstRowId() {
return firstRowId;
}
@Override
public Long addedRows() {
return addedRows;
}
@Override
public String keyId() {
return keyId;
}
private void cacheManifests(FileIO fileIO) {
if (fileIO == null) {
throw new IllegalArgumentException("Cannot cache changes: FileIO is null");
}
if (allManifests == null && v1ManifestLocations != null) {
// if we have a collection of manifest locations, then we need to load them here
allManifests =
Lists.transform(
Arrays.asList(v1ManifestLocations),
location ->
new GenericManifestFile(fileIO.newInputFile(location), 0, this.snapshotId));
}
if (allManifests == null) {
// if manifests isn't set, then the snapshotFile is set and should be read to get the list
this.allManifests =
ManifestLists.read(
ManifestLists.newInputFile(
fileIO, new BaseManifestListFile(manifestListLocation, keyId)));
}View on GitHub (pinned to 86d9c8fc54)