{"record":{"id":"cd7c21ba6b24e21b","repo":"apache/iceberg","slug":"cannot-apply-unknown-table-change-cd7c21","errorCode":null,"errorMessage":"Cannot apply unknown table change: ","messagePattern":"Cannot apply unknown table change: ","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/util/FlinkAlterTableUtil.java","lineNumber":149,"sourceCode":"      } else if (change instanceof TableChange.DropColumn) {\n        TableChange.DropColumn dropColumn = (TableChange.DropColumn) change;\n        pendingUpdate.deleteColumn(dropColumn.getColumnName());\n      } else if (change instanceof TableChange.AddWatermark) {\n        throw new UnsupportedOperationException(\"Unsupported table change: AddWatermark.\");\n      } else if (change instanceof TableChange.ModifyWatermark) {\n        throw new UnsupportedOperationException(\"Unsupported table change: ModifyWatermark.\");\n      } else if (change instanceof TableChange.DropWatermark) {\n        throw new UnsupportedOperationException(\"Unsupported table change: DropWatermark.\");\n      } else if (change instanceof TableChange.AddUniqueConstraint) {\n        TableChange.AddUniqueConstraint addPk = (TableChange.AddUniqueConstraint) change;\n        applyUniqueConstraint(pendingUpdate, addPk.getConstraint());\n      } else if (change instanceof TableChange.ModifyUniqueConstraint) {\n        TableChange.ModifyUniqueConstraint modifyPk = (TableChange.ModifyUniqueConstraint) change;\n        applyUniqueConstraint(pendingUpdate, modifyPk.getNewConstraint());\n      } else if (change instanceof TableChange.DropConstraint) {\n        throw new UnsupportedOperationException(\"Unsupported table change: DropConstraint.\");\n      } else {\n        throw new UnsupportedOperationException(\"Cannot apply unknown table change: \" + change);\n      }\n    }\n  }\n\n  private static void applyAddColumn(UpdateSchema pendingUpdate, TableChange.AddColumn addColumn) {\n    Column flinkColumn = addColumn.getColumn();\n    Preconditions.checkArgument(\n        FlinkCompatibilityUtil.isPhysicalColumn(flinkColumn),\n        \"Unsupported table change: Adding computed column %s.\",\n        flinkColumn.getName());\n\n    Type icebergType = FlinkSchemaUtil.convert(flinkColumn.getDataType().getLogicalType());\n\n    if (flinkColumn.getDataType().getLogicalType().isNullable()) {\n      pendingUpdate.addColumn(\n          flinkColumn.getName(), icebergType, flinkColumn.getComment().orElse(null));\n    } else {\n      pendingUpdate.addRequiredColumn(","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.3/flink/src/main/java/org/apache/iceberg/flink/util/FlinkAlterTableUtil.java#L131-L167","documentation":"FlinkAlterTableUtil.applySchemaChanges converts Flink TableChange objects into Iceberg UpdateSchema operations. When it encounters a TableChange subtype it has no mapping for, it throws UnsupportedOperationException. This guards against silently ignoring schema changes that Iceberg cannot represent.","triggerScenarios":"Calling ALTER TABLE with a change type not handled by the instanceof chain in applySchemaChanges (e.g. DropConstraint or a new Flink TableChange subtype added in a newer Flink version).","commonSituations":"Running `ALTER TABLE t DROP CONSTRAINT` or constraint-manipulation DDL through the Flink Iceberg catalog; using a Flink SQL feature whose change type predates Iceberg's support; upgrading Flink and relying on newly added TableChange subtypes.","solutions":["Avoid DDL that produces the unsupported change type (e.g. do not DROP constraints; instead use UPDATE on identifier fields via a fresh UpdateSchema).","Check supported change types in FlinkAlterTableUtil.applySchemaChanges and use an equivalent supported change.","Set identifier fields directly with table.updateSchema().setIdentifierFields(...) instead of constraint-based DDL.","Upgrade Iceberg to a version that supports the change type."],"exampleFix":"// before\nALTER TABLE iceberg_table DROP CONSTRAINT pk;\n// after\n-- not supported via Flink DDL; use:\nTable table = ...; table.updateSchema().setIdentifierFields(\"id\").commit();","handlingStrategy":"try-catch","validationCode":"// java\nboolean supported = changes.stream().allMatch(c ->\n    c instanceof TableChange.AddColumn || c instanceof TableChange.DeleteColumn\n    || c instanceof TableChange.ModifyColumn || c instanceof TableChange.ModifyUniqueConstraint);\nif (!supported) { throw new IllegalArgumentException(\"change type not supported by Iceberg Flink catalog\"); }","typeGuard":"boolean isSupportedChange(TableChange c) {\n  return c instanceof TableChange.AddColumn\n      || c instanceof TableChange.DeleteColumn\n      || c instanceof TableChange.ModifyColumn\n      || c instanceof TableChange.ModifyUniqueConstraint;\n}","tryCatchPattern":"try {\n  FlinkAlterTableUtil.applySchemaChanges(update, changes);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().startsWith(\"Cannot apply unknown table change\")) {\n    // fall back to direct UpdateSchema API\n  } else { throw e; }\n}","preventionTips":["Review applySchemaChanges' instanceof chain before issuing constraint DDL.","Avoid DROP CONSTRAINT and constraint DDL on Iceberg tables via Flink.","Pin Iceberg/Flink module versions together to avoid unknown change subtypes.","Use the Table.updateSchema() API directly for anything exotic."],"tags":["flink","unsupported-operation","schema-change"],"backgroundTag":"unsupported-operation","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}