apache/iceberg · error · IllegalArgumentException

Unsupported changelog scan task type: ${task.getClass().getN

Error message

Unsupported changelog scan task type: ${task.getClass().getName()}

What it means

ChangelogRowReader throws IllegalArgumentException when a ChangelogScanTask instance is none of the three supported types (AddedRowsScanTask, DeletedRowsScanTask, DeletedDataFileScanTask). This indicates the scan planner produced a task type the row reader cannot handle, typically due to version skew.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/ChangelogRowReader.java:110

    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();
    SparkDeleteFilter deletes =
        new SparkDeleteFilter(filePath, task.existingDeletes(), counter(), true);
    return deletes.filter(rows(task, deletes.requiredSchema()));
  }

  private CloseableIterable<InternalRow> rows(ContentScanTask<DataFile> task, Schema readSchema) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Ensure a single consistent Iceberg Spark runtime version on the classpath
  2. Check for shaded/conflicting iceberg jars in the Spark session
  3. Verify no custom ChangelogScanTask implementations are registered

Example fix

// before
// mixed iceberg-spark-runtime 4.1 and iceberg-core 4.2 jars
// after
// single matching runtime
implementation("org.apache.iceberg:iceberg-spark-runtime-4.2_2.13:<same-version-everywhere>")
Defensive patterns

Strategy: try-catch

Validate before calling

if (!(task instanceof AddedRowsScanTask || task instanceof DeletedRowsScanTask || task instanceof DeletedDataFileScanTask)) { throw before processing }

Type guard

boolean isKnownChangelogTask(ChangelogScanTask t) { return t instanceof AddedRowsScanTask || t instanceof DeletedRowsScanTask || t instanceof DeletedDataFileScanTask; }

Prevention

When it happens

Trigger: An unrecognized ChangelogScanTask subclass from a newer/older Iceberg runtime reaches openChangelogScanTask during changelog streaming.

Common situations: Mixing Iceberg jar versions (planner from one version, reader from another); custom scan task implementations injected via extensions.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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