{"record":{"id":"0537fcaebda05e5c","repo":"apache/iceberg","slug":"deleted-rows-scan-task-is-not-supported-yet-0537fc","errorCode":null,"errorMessage":"Deleted rows scan task is not supported yet","messagePattern":"Deleted rows scan task is not supported yet","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/ChangelogRowReader.java","lineNumber":104,"sourceCode":"    return cdcRows.iterator();\n  }\n\n  private static InternalRow changelogMetadata(ChangelogScanTask task) {\n    InternalRow metadataRow = new GenericInternalRow(3);\n\n    metadataRow.update(0, UTF8String.fromString(task.operation().name()));\n    metadataRow.update(1, task.changeOrdinal());\n    metadataRow.update(2, task.commitSnapshotId());\n\n    return metadataRow;\n  }\n\n  private CloseableIterable<InternalRow> openChangelogScanTask(ChangelogScanTask task) {\n    if (task instanceof AddedRowsScanTask) {\n      return openAddedRowsScanTask((AddedRowsScanTask) task);\n\n    } else if (task instanceof DeletedRowsScanTask) {\n      throw new UnsupportedOperationException(\"Deleted rows scan task is not supported yet\");\n\n    } else if (task instanceof DeletedDataFileScanTask) {\n      return openDeletedDataFileScanTask((DeletedDataFileScanTask) task);\n\n    } else {\n      throw new IllegalArgumentException(\n          \"Unsupported changelog scan task type: \" + task.getClass().getName());\n    }\n  }\n\n  CloseableIterable<InternalRow> openAddedRowsScanTask(AddedRowsScanTask task) {\n    String filePath = task.file().location();\n    SparkDeleteFilter deletes = new SparkDeleteFilter(filePath, task.deletes(), counter(), true);\n    return deletes.filter(rows(task, deletes.requiredSchema()));\n  }\n\n  private CloseableIterable<InternalRow> openDeletedDataFileScanTask(DeletedDataFileScanTask task) {\n    String filePath = task.file().location();","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/ChangelogRowReader.java#L86-L122","documentation":"ChangelogRowReader.openChangelogScanTask explicitly refuses DeletedRowsScanTask with an UnsupportedOperationException. Deleted-row tasks represent per-row deletes from equality deletes that this changelog reader does not implement; it supports added rows and deleted data files instead.","triggerScenarios":"A streaming changelog scan plan yields a DeletedRowsScanTask (rows deleted via equality deletes without a deleted data file) and the reader attempts to open it.","commonSituations":"Reading a v2 table's changelog where deletes were expressed as equality deletes (e.g. MERGE INTO / DELETE with an equality predicate); DELETE-only mode streaming without changelog support configured.","solutions":["Read the table in delete-only mode (read.stream with delete mode) instead of changelog mode","Rewrite deletes as copy-on-write (delete.mode=copy-on-write) so deletions produce deleted data files the reader supports","Rewrite manifests/data files to convert equality deletes into positional deletes or rewritten files","Upgrade Iceberg if a newer version adds DeletedRowsScanTask support"],"exampleFix":"// before\nspark.readStream.option(\"streaming-changelog-enabled\", \"true\").table(\"t\")\n// after\nspark.readStream.option(\"streaming-delete-handling-mode\", \"delete\").table(\"t\")","handlingStrategy":"fallback","validationCode":"if (task instanceof DeletedRowsScanTask) { /* switch to delete-only mode or rewrite deletes */ }","typeGuard":"boolean supported(ChangelogScanTask t) { return t instanceof AddedRowsScanTask || t instanceof DeletedDataFileScanTask; }","tryCatchPattern":"try { open(task) } catch (UnsupportedOperationException e) { fall back to delete-only read mode }","preventionTips":["Use copy-on-write delete mode for tables read in changelog mode","Avoid equality deletes on changelog-consumed tables","Prefer delete-only streaming mode when row-level delete events are not required"],"tags":["spark","streaming","changelog","deletes"],"backgroundTag":"unsupported-operation","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"}