{"record":{"id":"2098b60b492314da","repo":"apache/iceberg","slug":"failed-to-close-changelog-scan-scan","errorCode":null,"errorMessage":"Failed to close changelog scan: ${scan}","messagePattern":"Failed to close changelog scan: (.+?)","errorType":"exception","errorClass":"UncheckedIOException","httpStatus":null,"severity":"error","filePath":"spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkChangelogScan.java","lineNumber":122,"sourceCode":"  @Override\n  public Batch toBatch() {\n    return new SparkBatch(\n        sparkContext,\n        table,\n        null != scan ? scan.fileIO() : table::io,\n        readConf,\n        EMPTY_GROUPING_KEY_TYPE,\n        taskGroups(),\n        expectedSchema,\n        hashCode());\n  }\n\n  private List<ScanTaskGroup<ChangelogScanTask>> taskGroups() {\n    if (taskGroups == null) {\n      try (CloseableIterable<ScanTaskGroup<ChangelogScanTask>> groups = scan.planTasks()) {\n        this.taskGroups = Lists.newArrayList(groups);\n      } catch (IOException e) {\n        throw new UncheckedIOException(\"Failed to close changelog scan: \" + scan, e);\n      }\n    }\n\n    return taskGroups;\n  }\n\n  @Override\n  public String description() {\n    return String.format(\n        Locale.ROOT,\n        \"%s [fromSnapshotId=%d, toSnapshotId=%d, filters=%s]\",\n        table,\n        startSnapshotId,\n        endSnapshotId,\n        Spark3Util.describe(filters));\n  }\n\n  @Override","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/SparkChangelogScan.java#L104-L140","documentation":"taskGroups() plans changelog tasks via scan.planTasks() inside try-with-resources; if closing the resulting CloseableIterable throws IOException, the planning failure is wrapped as UncheckedIOException with the scan description. The scan itself failed to plan/close cleanly, usually an underlying FileIO error.","triggerScenarios":"Calling tasks()/taskGroups() on SparkChangelogScan when planTasks() or the closing of the planned task iterable throws IOException (e.g. missing manifest files, filesystem outage).","commonSituations":"Corrupt or deleted manifest/metadata files, S3/HDFS transient errors, or snapshot expiry racing a changelog scan in Spark structured streaming.","solutions":["Inspect the cause chain for the underlying FileIO/filesystem error and fix that (missing file, credentials, network).","Verify all referenced manifests/snapshots exist and the table metadata is consistent (run validate/expire checks).","Retry the scan; if transient cloud-storage errors recur, add retries or check endpoint/credentials."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before streaming: verify table metadata is readable\nTableMetadataParser.read(io, metadataLoc); // throws if metadata/manifests unreadable","typeGuard":null,"tryCatchPattern":"try { ... } catch (UncheckedIOException e) { log.error(\"changelog plan failed: {}\", e.getCause()); throw e; }","preventionTips":["Keep manifest/metadata files intact; avoid expiring snapshots concurrently with changelog reads","Ensure storage credentials/permissions for the table location","Add retry with backoff for transient cloud storage errors"],"tags":["spark","changelog","io","scan-planning"],"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"}