apache/iceberg · error · UncheckedIOException
Failed to close scan: ${scan}
Error message
Failed to close scan: ${scan} What it means
SparkPartitioningAwareScan.tasks() plans scan tasks inside try-with-resources; an IOException while closing the planned task iterable is wrapped as UncheckedIOException with the scan description. This signals the scan failed to complete/close cleanly, typically an underlying FileIO failure.
Source
Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkPartitioningAwareScan.java:196
protected synchronized List<T> tasks() {
if (tasks == null) {
try (CloseableIterable<? extends ScanTask> taskIterable = scan.planFiles()) {
List<T> plannedTasks = Lists.newArrayList();
for (ScanTask task : taskIterable) {
ValidationException.check(
taskJavaClass().isInstance(task),
"Unsupported task type, expected a subtype of %s: %s",
taskJavaClass().getName(),
task.getClass().getName());
plannedTasks.add(taskJavaClass().cast(task));
}
this.tasks = plannedTasks;
} catch (IOException e) {
throw new UncheckedIOException("Failed to close scan: " + scan, e);
}
}
return tasks;
}
@Override
protected synchronized List<ScanTaskGroup<T>> taskGroups() {
if (taskGroups == null) {
if (groupingKeyType().fields().isEmpty()) {
CloseableIterable<ScanTaskGroup<T>> plannedTaskGroups =
TableScanUtil.planTaskGroups(
CloseableIterable.withNoopClose(tasks()),
adjustSplitSize(tasks(), scan.targetSplitSize()),
scan.splitLookback(),
scan.splitOpenFileCost());
this.taskGroups = Lists.newArrayList(plannedTaskGroups);
View on GitHub (pinned to 86d9c8fc54)
Solutions
- Inspect the cause chain for the real FileIO error (missing file, auth, network) and fix it.
- Validate table metadata/manifest availability; re-run the query after transient storage issues clear.
- If caused by concurrent expiry, avoid expiring snapshots while queries are planning against them.
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight: read table metadata and list manifests before planning table.refresh(); table.currentSnapshot().allManifests(table.io()); // throws if manifests unreadable
Try / catch
try { scan.tasks(); } catch (UncheckedIOException e) { log.error("scan close failed: {} cause={}", scan, e.getCause()); throw e; } Prevention
- Avoid concurrent snapshot expiry during query planning
- Validate table metadata integrity after storage incidents
- Retry planning on transient cloud storage failures
When it happens
Trigger: Calling tasks() during Spark planning when planFiles()/planTasks() close throws IOException — missing manifests, filesystem errors, expired snapshots.
Common situations: Metadata corruption, concurrent snapshot expiry, or transient cloud storage errors while a Spark query plans an Iceberg scan.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to close changelog scan: ${scan}
- Failed to close scan: + scan
- Failed to close scan: ${scan}
- Failed to list partitions of table %s
- Failed to plan files for main index
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/afcf00340bf3a69c.
Report an issue: GitHub.