apache/iceberg · error · UnsupportedOperationException

Unsupported table change: AddWatermark.

Error message

Unsupported table change: AddWatermark.

What it means

FlinkAlterTableUtil.applySchemaChanges maps Flink TableChange objects onto Iceberg UpdateSchema operations. Iceberg tables do not support watermarks, so an AddWatermark change is rejected with UnsupportedOperationException. The change is never applied and the ALTER fails.

Source

Thrown at flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/util/FlinkAlterTableUtil.java:135

  /**
   * Applies a list of Flink table changes to an {@link UpdateSchema} operation.
   *
   * @param pendingUpdate an uncommitted UpdateSchema operation to configure
   * @param schemaChanges a list of Flink table changes
   */
  public static void applySchemaChanges(
      UpdateSchema pendingUpdate, List<TableChange> schemaChanges) {
    for (TableChange change : schemaChanges) {
      if (change instanceof TableChange.AddColumn) {
        applyAddColumn(pendingUpdate, (TableChange.AddColumn) change);
      } else if (change instanceof TableChange.ModifyColumn) {
        TableChange.ModifyColumn modifyColumn = (TableChange.ModifyColumn) change;
        applyModifyColumn(pendingUpdate, modifyColumn);
      } 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);
      }
    }
  }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Remove the ADD WATERMARK statement; express event-time logic in the Flink job's SELECT instead (watermark on the source/derived table view)
  2. Define the watermark on a Flink VIEW over the Iceberg table rather than on the Iceberg table itself
  3. Patch via custom catalog if watermark semantics are truly needed (not supported upstream)

Example fix

-- before
ALTER TABLE iceberg_table ADD WATERMARK FOR rowtime AS rowtime - INTERVAL '5' SECOND;
-- after
CREATE VIEW v AS SELECT *, rowtime - INTERVAL '5' SECOND AS wm FROM iceberg_table; -- watermark on view/source
Defensive patterns

Strategy: try-catch

Validate before calling

// before ALTER
if (changes.stream().anyMatch(c -> c instanceof TableChange.AddWatermark)) {
  throw new IllegalArgumentException("Watermark DDL is not supported on Iceberg tables");
}

Type guard

boolean isWatermarkChange(TableChange c) { return c instanceof TableChange.AddWatermark || c instanceof TableChange.ModifyWatermark || c instanceof TableChange.DropWatermark; }

Try / catch

try {
  FlinkAlterTableUtil.applySchemaChanges(update, changes);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("AddWatermark")) { /* move watermark to a view or source */ }
  throw e;
}

Prevention

When it happens

Trigger: Executing a Flink SQL 'ALTER TABLE ... ADD WATERMARK' (or calling TableEnvironment/DynamicCatalog with a TableChange.AddWatermark) against a table backed by the Iceberg catalog.

Common situations: Porting SQL written for Flink's built-in connector tables (which support watermarks) to Iceberg tables.

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/898f642ad324b97c. Report an issue: GitHub.