apache/iceberg · error · UnsupportedOperationException

Deleted rows scan task is not supported yet

Error message

Deleted rows scan task is not supported yet

What it means

ChangelogRowReader.openChangelogScanTask dispatches on ChangelogScanTask subtypes. DeletedRowsScanTask (equality-delete-generated deleted rows for streaming changelog) has no reader implementation yet, so an UnsupportedOperationException is thrown. The changelog reader supports added rows and deleted data files but not this task kind.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/ChangelogRowReader.java:108

    return cdcRows.iterator();
  }

  private static InternalRow changelogMetadata(ChangelogScanTask task) {
    InternalRow metadataRow = new GenericInternalRow(3);

    metadataRow.update(0, UTF8String.fromString(task.operation().name()));
    metadataRow.update(1, task.changeOrdinal());
    metadataRow.update(2, task.commitSnapshotId());

    return metadataRow;
  }

  private CloseableIterable<InternalRow> openChangelogScanTask(ChangelogScanTask task) {
    if (task instanceof AddedRowsScanTask) {
      return openAddedRowsScanTask((AddedRowsScanTask) task);

    } else if (task instanceof DeletedRowsScanTask) {
      throw new UnsupportedOperationException("Deleted rows scan task is not supported yet");

    } else if (task instanceof DeletedDataFileScanTask) {
      return openDeletedDataFileScanTask((DeletedDataFileScanTask) task);

    } else {
      throw new IllegalArgumentException(
          "Unsupported changelog scan task type: " + task.getClass().getName());
    }
  }

  CloseableIterable<InternalRow> openAddedRowsScanTask(AddedRowsScanTask task) {
    String filePath = task.file().location();
    SparkDeleteFilter deletes = new SparkDeleteFilter(filePath, task.deletes(), counter(), true);
    return deletes.filter(rows(task, deletes.requiredSchema()));
  }

  private CloseableIterable<InternalRow> openDeletedDataFileScanTask(DeletedDataFileScanTask task) {
    String filePath = task.file().location();

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Avoid equality deletes in the table; use copy-on-write mode so deletions appear as DeletedDataFileScanTask instead.
  2. Rewrite/compact the table (rewrite_data_files with delete handling) to remove equality delete files.
  3. Disable changelog streaming for this table or use incremental append mode if deletes are not needed.
  4. Upgrade Iceberg; support for deleted-rows tasks may be added in later versions.

Example fix

// before
spark.readStream.format("iceberg").option("streaming-row-changelog", "true").load("db.t")
// after (use copy-on-write table so deletes yield data-file tasks)
ALTER TABLE db.t SET TBLPROPERTIES ('write.delete.mode'='copy-on-write');
Defensive patterns

Strategy: validation

Validate before calling

Table table = catalog.loadTable("db.t");
if (table.spec().isPartitioned() && Boolean.parseBoolean(table.properties().getOrDefault("write.delete.mode", "merge-on-read")) == false) {
  // merge-on-read with equality deletes can produce DeletedRowsScanTask
}
boolean hasEqDeletes = table.scans().stream().anyMatch(s -> true); // ensure no equality delete files remain
DeleteFiles deletes = table.currentSnapshot().dataManifests(table.io()).stream()
    .filter(m -> m.hasEqualDeletes()).count() > 0 ? null : null;

Type guard

boolean supportsChangelog(ChangelogScanTask task) {
  return task instanceof AddedRowsScanTask || task instanceof DeletedDataFileScanTask;
}

Try / catch

try {
  changelogDf.writeStream().start();
} catch (StreamingQueryException e) {
  if (e.getCause() instanceof UnsupportedOperationException
      && e.getCause().getMessage().contains("Deleted rows scan task is not supported")) {
    // switch table to copy-on-write or fall back to incremental mode
  } else { throw e; }
}

Prevention

When it happens

Trigger: Using the streaming read with streaming-row-changelog enabled (includeColumnStats/stream-changelog) on a table where a commit produced DeletedRowsScanTask, i.e. rows removed via equality/mor deletes without deleting whole data files.

Common situations: Streaming changelog reads over tables using merge-on-read equality deletes; updates expressed as delete records in v2 tables.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/9a5652b11852a7a1. Report an issue: GitHub.