apache/iceberg · error · IllegalStateException

Unexpected ContentScanTask type:

Error message

Unexpected ContentScanTask type: 

What it means

Thrown by EqualityConvertReader.processElement when a ContentScanTask in a ReadCommand is neither a data-file task nor an EqualityDeleteFileScanTask. The reader dispatches on task type and fails with the concrete class name; the error is also emitted to the error stream and an ABORT is signaled on READER_ABORT_STREAM.

Source

Thrown at flink/v2.3/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)

Solutions

  1. Run all maintenance operators from the same Iceberg build; restart from a savepoint created by that same version.
  2. Identify the unexpected class from the message and add a corresponding handler branch if it is a legitimate new task type from your fork.
  3. Restore the stock planner/reader pipeline if custom modifications introduced the mismatch.

Example fix

// before: planner from v1.9 emitting new task type, reader from v1.6
StreamExecutionEnvironment env = ...; // operators built from two jars
// after: build the whole job graph from one Iceberg version
env.fromSavepoint(sameVersionSavepoint); // all operators same jar/version
Defensive patterns

Strategy: type-guard

Type guard

// before sending a ReadCommand downstream
if (!(cmd.scanTask() instanceof DataFileScanTask)
    && !(cmd.scanTask() instanceof EqualityDeleteFileScanTask)) {
  throw new IllegalArgumentException("Reader cannot handle task " + cmd.scanTask().getClass());
}

Try / catch

// Reader already reports failures via side outputs
DataStream<?> readerOut = planner.getSideOutput(...).process(new EqualityConvertReader(...));
readerOut.getSideOutput(READER_ABORT_STREAM).process(new AbortHandler()); // react to ABORT instead of crashing the job

Prevention

When it happens

Trigger: A planner-emitted ReadCommand carries a ContentScanTask subtype the reader doesn't handle — typically after mixed operator versions (planner newer than reader), or custom pipeline modifications inserting new task types (e.g. other delete-scan tasks).

Common situations: Partial rolling upgrade of the Flink job with a savepoint from a different Iceberg version; hand-edited or forked planner code emitting tasks like DeleteFileIndex scan tasks the reader was not built for.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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