apache/iceberg · error · UnsupportedOperationException

Cannot apply unknown table change:

Error message

Cannot apply unknown table change: 

What it means

The default branch of applySchemaChanges throws this when a TableChange instance is not one of the recognized change types (add/modify/rename/drop column, unique-constraint changes, etc.). It indicates an unknown or newly introduced Flink TableChange subtype reached an older/exhaustive switch that does not handle it.

Source

Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/util/FlinkAlterTableUtil.java:149

      } else if (change instanceof TableChange.DropColumn) {
        TableChange.DropColumn dropColumn = (TableChange.DropColumn) change;
        pendingUpdate.deleteColumn(dropColumn.getColumnName());
      } else if (change instanceof TableChange.AddWatermark) {
        throw new UnsupportedOperationException("Unsupported table change: AddWatermark.");
      } else if (change instanceof TableChange.ModifyWatermark) {
        throw new UnsupportedOperationException("Unsupported table change: ModifyWatermark.");
      } else if (change instanceof TableChange.DropWatermark) {
        throw new UnsupportedOperationException("Unsupported table change: DropWatermark.");
      } else if (change instanceof TableChange.AddUniqueConstraint) {
        TableChange.AddUniqueConstraint addPk = (TableChange.AddUniqueConstraint) change;
        applyUniqueConstraint(pendingUpdate, addPk.getConstraint());
      } else if (change instanceof TableChange.ModifyUniqueConstraint) {
        TableChange.ModifyUniqueConstraint modifyPk = (TableChange.ModifyUniqueConstraint) change;
        applyUniqueConstraint(pendingUpdate, modifyPk.getNewConstraint());
      } else if (change instanceof TableChange.DropConstraint) {
        throw new UnsupportedOperationException("Unsupported table change: DropConstraint.");
      } else {
        throw new UnsupportedOperationException("Cannot apply unknown table change: " + change);
      }
    }
  }

  private static void applyAddColumn(UpdateSchema pendingUpdate, TableChange.AddColumn addColumn) {
    Column flinkColumn = addColumn.getColumn();
    Preconditions.checkArgument(
        FlinkCompatibilityUtil.isPhysicalColumn(flinkColumn),
        "Unsupported table change: Adding computed column %s.",
        flinkColumn.getName());

    Type icebergType = FlinkSchemaUtil.convert(flinkColumn.getDataType().getLogicalType());

    if (flinkColumn.getDataType().getLogicalType().isNullable()) {
      pendingUpdate.addColumn(
          flinkColumn.getName(), icebergType, flinkColumn.getComment().orElse(null));
    } else {
      pendingUpdate.addRequiredColumn(

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Upgrade iceberg-flink-runtime to a version matching your Flink version so all change types are handled
  2. Log and inspect the change's class name to identify the unhandled type
  3. Pre-filter the TableChange list and reject unsupported types before calling applySchemaChanges

Example fix

// before
UnsupportedOperationException: Cannot apply unknown table change: ...
// after
if (!(change instanceof TableChange.AddColumn
    || change instanceof TableChange.ModifyColumn)) {
  throw new IllegalArgumentException("Unsupported change: " + change.getClass().getName());
}
Defensive patterns

Strategy: type-guard

Validate before calling

Set<Class<?>> supported = Set.of(TableChange.AddColumn.class, TableChange.ModifyColumn.class, TableChange.RenameColumn.class, TableChange.DropColumn.class, TableChange.AddUniqueConstraint.class, TableChange.ModifyUniqueConstraint.class);
boolean ok = changes.stream().allMatch(c -> supported.contains(c.getClass()));
if (!ok) throw new IllegalArgumentException("Change list contains unsupported types");

Type guard

static boolean isKnownSchemaChange(TableChange c) {
  return c instanceof TableChange.AddColumn || c instanceof TableChange.ModifyColumn
      || c instanceof TableChange.RenameColumn || c instanceof TableChange.DropColumn
      || c instanceof TableChange.ModifyColumnPosition || c instanceof TableChange.AddUniqueConstraint
      || c instanceof TableChange.ModifyUniqueConstraint;
}

Try / catch

try { FlinkAlterTableUtil.applySchemaChanges(update, changes); }
catch (UnsupportedOperationException e) {
  if (e.getMessage().startsWith("Cannot apply unknown table change")) { log.warn("Unhandled change type; upgrade runtime", e); }
  throw e;
}

Prevention

When it happens

Trigger: Passing a TableChange subtype not handled by FlinkAlterTableUtil (e.g. a change type added in a newer Flink version or a custom TableChange) into catalog.alterTable / applySchemaChanges.

Common situations: Flink/Iceberg version skew where the Flink planner emits new change types; custom catalog wrappers forwarding unfiltered change lists; typos in change handling code.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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