apache/iceberg · error · IllegalStateException
Unexpected ContentScanTask type:
Error message
Unexpected ContentScanTask type:
What it means
The EqualityConvertReader dispatches each ReadCommand's ContentScanTask to a processor by concrete type (data file task, staging task, or EqualityDeleteFileScanTask). If a task of an unknown ContentScanTask subtype arrives, the reader throws IllegalStateException naming the class. The exception is caught, logged, and forwarded on the ERROR_STREAM and READER_ABORT_STREAM so the maintenance task fails cleanly.
Solutions
- Ensure the planner (EqualityConvertPlanner) and reader come from the same Iceberg/Flink build; do not restore from a savepoint taken with a different version.
- Log the task class name (included in the message) and add the corresponding instanceof branch or upgrade Iceberg to the version that supports that task type.
- Discard in-flight commands and re-trigger the maintenance cycle so the planner re-plans with current task types.
Defensive patterns
Strategy: type-guard
Validate before calling
// before submitting commands downstream
if (!(task instanceof IniCloseableIterable)) { /* see guard */ }
if (!(task instanceof DataFileScanTask || task instanceof EqualityDeleteFileScanTask)) {
throw new IllegalArgumentException("Unsupported task type: " + task.getClass());
} Type guard
static boolean isSupportedTask(ContentScanTask<?> task) {
return task instanceof DataFileScanTask
|| task instanceof EqualityDeleteFileScanTask;
} Try / catch
try {
processElement(cmd, ctx, out);
} catch (IllegalStateException e) {
LOG.error("Unsupported scan task {}; re-planning required", e.getMessage());
ctx.output(TaskResultAggregator.ERROR_STREAM, e);
} Prevention
- Keep planner and reader on the same Iceberg/Flink build
- Avoid restoring savepoints across incompatible Iceberg versions
- Re-trigger planning after upgrades instead of replaying old in-flight commands
When it happens
Trigger: processElement receives a ReadCommand whose scan task is neither an expected data-file scan task nor an EqualityDeleteFileScanTask — e.g. after an Iceberg/Flink version change introduces a new ContentScanTask implementation, or a command was serialized by a different planner version.
Common situations: Mixing maintenance job versions: a checkpoint/savepoint restored commands planned by an older or newer planner that emits a task type this reader does not know; custom scan task implementations injected upstream.
Related errors
- Duplicate id:
- errMsg(variant, "double")
- errMsg(variant, "int")
- errMsg(variant, "long")
- errMsg(variant, "timestamp")
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/47289162f72369ac.
Report an issue: GitHub.
Appendix: source
Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/operator/EqualityConvertReader.java:126
@Override
public void processElement(ReadCommand cmd, Context ctx, Collector<IndexCommand> out)
throws Exception {
ContentScanTask<?> task = cmd.task();
ContentFile<?> file = task.file();
try {
if (task instanceof FileScanTask dataTask) {
processDataFile(
dataTask,
cmd.mainSnapshotId(),
cmd.indexGeneration(),
cmd.dataSequenceNumber(),
cmd.staging(),
out);
} else if (task instanceof EqualityDeleteFileScanTask deleteTask) {
processDeleteFile(
deleteTask, cmd.mainSnapshotId(), cmd.indexGeneration(), cmd.dataSequenceNumber(), out);
} else {
throw new IllegalStateException(
"Unexpected ContentScanTask type: " + task.getClass().getName());
}
} catch (Exception e) {
LOG.error("Reader failed to process command for file={}", file.location(), e);
ctx.output(TaskResultAggregator.ERROR_STREAM, e);
ctx.output(READER_ABORT_STREAM, DVPosition.ABORT);
}
}
private void processDataFile(
FileScanTask task,
Long mainSnapshotId,
Long indexGeneration,
long dataSequenceNumber,
boolean staging,
Collector<IndexCommand> out)
throws IOException {
ContentFile<?> file = task.file();View on GitHub (pinned to 86d9c8fc54)