{"record":{"id":"a0b7a1ccf7aad26a","repo":"apache/iceberg","slug":"failed-to-close-scan-scan-a0b7a1","errorCode":null,"errorMessage":"Failed to close scan: ${scan}","messagePattern":"Failed to close scan: (.+?)","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkPartitioningAwareScan.java","lineNumber":197,"sourceCode":"\n  protected synchronized List<T> tasks() {\n    if (tasks == null) {\n      try (CloseableIterable<? extends ScanTask> taskIterable = scan.planFiles()) {\n        List<T> plannedTasks = Lists.newArrayList();\n\n        for (ScanTask task : taskIterable) {\n          ValidationException.check(\n              taskJavaClass().isInstance(task),\n              \"Unsupported task type, expected a subtype of %s: %s\",\n              taskJavaClass().getName(),\n              task.getClass().getName());\n\n          plannedTasks.add(taskJavaClass().cast(task));\n        }\n\n        this.tasks = plannedTasks;\n      } catch (IOException e) {\n        throw new UncheckedIOException(\"Failed to close scan: \" + scan, e);\n      }\n    }\n\n    return tasks;\n  }\n\n  @Override\n  protected synchronized List<ScanTaskGroup<T>> taskGroups() {\n    if (taskGroups == null) {\n      if (groupingKeyType().fields().isEmpty()) {\n        CloseableIterable<ScanTaskGroup<T>> plannedTaskGroups =\n            TableScanUtil.planTaskGroups(\n                CloseableIterable.withNoopClose(tasks()),\n                adjustSplitSize(tasks(), scan.targetSplitSize()),\n                scan.splitLookback(),\n                scan.splitOpenFileCost());\n        this.taskGroups = Lists.newArrayList(plannedTaskGroups);\n","sourceCodeStart":179,"sourceCodeEnd":215,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkPartitioningAwareScan.java#L179-L215","documentation":"SparkPartitioningAwareScan.tasks() plans tasks and closes the scan with CloseableIterable; if closing the planned scan throws IOException, it is wrapped in UncheckedIOException with the scan's description. This signals leaked/planning resources (file handles, manifest readers) could not be released after task planning.","triggerScenarios":"task planning completes but closing the CloseableIterable of tasks throws IOException — typically an underlying FileIO error while closing manifest readers or input streams during plan() cleanup.","commonSituations":"Filesystem or object-store connectivity errors during close (S3 timeouts, HDFS client errors); exhausted file descriptors causing close failures; buggy custom FileIO implementations that throw on close().","solutions":["Check the chained IOException cause for the underlying FileIO/close error and address it (network, permissions, custom FileIO bug)","Raise the process file-descriptor limit (ulimit) if fd exhaustion is reported","Use a well-tested FileIO implementation (HadoopFileIO / S3FileIO) instead of custom ones and retry the scan"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  tasks = scan.tasks();\n} catch (UncheckedIOException e) {\n  LOG.warn(\"Scan close failed, retrying\", e.getCause());\n  tasks = scan.tasks();\n}","preventionTips":["Raise ulimit -n if fd exhaustion is common","Prefer maintained FileIO implementations over custom ones","Retry scan planning on transient storage errors"],"tags":["spark","scan-planning","io","resource-cleanup"],"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"}