apache/iceberg · warning · UncheckedIOException
Failed to close table loader
Error message
Failed to close table loader
What it means
IcebergSource.planSplitsForBatch plans all batch splits during job initialization inside a try-with-resources on the TableLoader; if closing the TableLoader throws IOException, it is wrapped into an UncheckedIOException with this message. The worker pool is shut down in a finally block regardless. It indicates a failure releasing the table's FileIO resources after batch planning completed.
Solutions
- Inspect the wrapped IOException cause; it usually reflects an underlying filesystem close problem that is often benign — verify planning output was produced.
- Check Hadoop/HDFS client configuration and versions for known close/handle-leak bugs; align Hadoop client versions.
- Avoid forced cancellation during initialization; let batch planning and close finish.
- If reproducible, report with the cause stack; the planned splits are valid, so a retry typically succeeds.
Defensive patterns
Strategy: try-catch
Try / catch
try {
List<IcebergSourceSplit> splits = source.splits(...);
} catch (UncheckedIOException e) {
if (e.getCause() != null && isBenignCloseFailure(e.getCause())) {
LOG.warn("Table loader close failed after successful planning; ignoring", e);
} else { throw e; }
} Prevention
- Don't cancel jobs during batch initialization; wait for planning to finish.
- Keep Hadoop client versions consistent to avoid FileSystem close bugs.
- Log and classify close-time IOExceptions separately from planning failures.
When it happens
Trigger: Calling IcebergSource.splits (batch mode) where tableLoader.close() throws IOException after batch split discovery succeeds — e.g., Hadoop FileIO close failing on the underlying filesystem handle.
Common situations: Hadoop FileSystem close errors in long-lived jobs; interrupted close during job cancellation; misconfigured Hadoop filesystem caches releasing native resources.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- Failed to close table loader
- Failed to close table loader
- Failed to load iceberg table from table loader
- Failed to load iceberg table from table loader
- Failed to load iceberg table from table loader:
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/775c9bbf728eba07.
Report an issue: GitHub.
Appendix: source
Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/source/IcebergSource.java:166
*/
private List<IcebergSourceSplit> planSplitsForBatch(String threadName) {
if (batchSplits != null) {
return batchSplits;
}
ExecutorService workerPool =
ThreadPools.newFixedThreadPool(threadName, scanContext.planParallelism());
try (TableLoader loader = tableLoader.clone()) {
loader.open();
this.batchSplits =
FlinkSplitPlanner.planIcebergSourceSplits(loader.loadTable(), scanContext, workerPool);
LOG.info(
"Discovered {} splits from table {} during job initialization",
batchSplits.size(),
tableName);
return batchSplits;
} catch (IOException e) {
throw new UncheckedIOException("Failed to close table loader", e);
} finally {
workerPool.shutdown();
}
}
@Override
public Boundedness getBoundedness() {
return scanContext.isStreaming() ? Boundedness.CONTINUOUS_UNBOUNDED : Boundedness.BOUNDED;
}
@Override
public SourceReader<T, IcebergSourceSplit> createReader(SourceReaderContext readerContext) {
IcebergSourceReaderMetrics metrics =
new IcebergSourceReaderMetrics(readerContext.metricGroup(), tableName);
return new IcebergSourceReader<>(
emitter, metrics, readerFunction, splitComparator, readerContext);
}
View on GitHub (pinned to 86d9c8fc54)