apache/iceberg · error · IllegalArgumentException
Unsupported changelog scan task type:
Error message
Unsupported changelog scan task type:
What it means
ChangelogRowReader.openChangelogScanTask dispatches on the ChangelogScanTask subtype and throws IllegalArgumentException when the task type is none of AddedRowsScanTask, DeletedRowsScanTask, or DeletedDataFileScanTask. This guards against unknown/future task types produced by a mismatched scan planner.
Source
Thrown at spark/v4.1/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
- Align all Iceberg module versions (spark runtime + core) to the same release
- Check which task class name is printed in the message and whether it comes from a custom/old jar
- Remove duplicate/shaded Iceberg jars from the classpath
- Upgrade iceberg-spark to a release that supports the task type
Example fix
// before: mixed iceberg-core 1.6 with iceberg-spark 1.4 on classpath // after: use one version implementation 'org.apache.iceberg:iceberg-spark-runtime-4.1_2.13:1.6.1'
Defensive patterns
Strategy: type-guard
Validate before calling
// before reading changelog tasks
if (!(task instanceof AddedRowsScanTask) && !(task instanceof DeletedRowsScanTask) && !(task instanceof DeletedDataFileScanTask)) {
throw new IllegalStateException("Unsupported changelog task: " + task.getClass().getName());
} Type guard
boolean isSupportedChangelogTask(ChangelogScanTask t) {
return t instanceof AddedRowsScanTask || t instanceof DeletedRowsScanTask || t instanceof DeletedDataFileScanTask;
} Try / catch
try { reader.openChangelogScanTask(task); } catch (IllegalArgumentException e) { /* inspect task class, fix jar versions */ } Prevention
- Keep all Iceberg modules at the same version
- Run mvn/gradle dependency:tree to detect mixed iceberg jars
- Test changelog reads after upgrades
When it happens
Trigger: A ChangelogScanTask subclass not handled by the if/else chain reaches openChangelogScanTask, e.g. a new task type added in a newer Iceberg core while this Spark reader is older, or a custom scan task implementation.
Common situations: Version skew between iceberg-spark and iceberg-core jars on the classpath (mixed versions after upgrade); custom ChangelogScanTask implementations; internal bugs in scan planning.
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
- Unsupported manifest content type:${content}
- Cannot pass path based identifier to %s method. %s is a path
- Unsupported command: ${command}
- Unknown time travel: ${timeTravel}
- Unsupported Spark view dependency: ${dependency.getClass().g
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/4ac4f613f768332e.
Report an issue: GitHub.