{"record":{"id":"1ee79c6f3e4a0e5a","repo":"apache/iceberg","slug":"altering-schema-is-not-supported-in-the-old-altert","errorCode":null,"errorMessage":"Altering schema is not supported in the old alterTable API. To alter schema, use the other alterTable API and provide a list of TableChange's.","messagePattern":"Altering schema is not supported in the old alterTable API\\. To alter schema, use the other alterTable API and provide a list of TableChange's\\.","errorType":"exception","errorClass":"java.lang.UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/FlinkCatalog.java","lineNumber":478,"sourceCode":"    try {\n      icebergCatalog.createTable(\n          toIdentifier(tablePath), icebergSchema, spec, location, properties.build());\n    } catch (AlreadyExistsException e) {\n      if (!ignoreIfExists) {\n        throw new TableAlreadyExistException(getName(), tablePath, e);\n      }\n    }\n  }\n\n  private boolean isReservedProperty(String prop) {\n    return FlinkCreateTableOptions.LOCATION_KEY.equalsIgnoreCase(prop)\n        || FlinkCreateTableOptions.CONNECTOR_PROPS_KEY.equalsIgnoreCase(prop)\n        || FlinkCreateTableOptions.SRC_CATALOG_PROPS_KEY.equalsIgnoreCase(prop);\n  }\n\n  private static void validateTableSchemaAndPartition(CatalogTable ct1, CatalogTable ct2) {\n    if (!Objects.equals(ct1.getUnresolvedSchema(), ct2.getUnresolvedSchema())) {\n      throw new UnsupportedOperationException(\n          \"Altering schema is not supported in the old alterTable API. \"\n              + \"To alter schema, use the other alterTable API and provide a list of TableChange's.\");\n    }\n\n    validateTablePartition(ct1, ct2);\n  }\n\n  private static void validateTablePartition(CatalogTable ct1, CatalogTable ct2) {\n    if (!ct1.getPartitionKeys().equals(ct2.getPartitionKeys())) {\n      throw new UnsupportedOperationException(\"Altering partition keys is not supported yet.\");\n    }\n  }\n\n  /**\n   * This alterTable API only supports altering table properties.\n   *\n   * <p>Support for adding/removing/renaming columns cannot be done by comparing CatalogTable\n   * instances, unless the Flink schema contains Iceberg column IDs.","sourceCodeStart":460,"sourceCodeEnd":496,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/FlinkCatalog.java#L460-L496","documentation":"The deprecated/legacy Flink Catalog.alterTable(ObjectPath, CatalogTable, boolean) API cannot change a table's schema; FlinkCatalog.validateTableSchemaAndPartition compares the unresolved schemas of the existing and new CatalogTable and throws UnsupportedOperationException when they differ. Schema evolution must go through the TableChange-based alterTable API.","triggerScenarios":"Calling alterTable(tablePath, newCatalogTable, ignoreIfNotExists) where newCatalogTable's unresolved schema differs from the current table's — e.g. adding, dropping, renaming, or retyping a column via full-table replacement.","commonSituations":"Older Flink job/framework code that still uses the legacy alterTable signature to add a column; hand-written migration scripts that rewrite the whole CatalogTable; upgrading code written before the TableChange API existed.","solutions":["Use the TableChange-based alterTable: ALTER TABLE in Flink SQL (ALTER TABLE t ADD (c INT)) or catalog.alterTable(path, List<TableChange>, ignoreIfNotExists) with UpdateRequirements/UpdateOptions as appropriate.","If only properties changed, verify the schema is byte-identical so the legacy API is safe, or migrate the call anyway.","Upgrade the caller to Flink's newer catalog API surface that supports TableChange."],"exampleFix":"// before\ncatalog.alterTable(path, tableWithNewColumn, false);\n// after\ncatalog.alterTable(path, java.util.Arrays.asList(TableChange.addColumn(\"c\", DataTypes.INT())), false);","handlingStrategy":"validation","validationCode":"// compare schemas before legacy alterTable\nif (!current.getUnresolvedSchema().equals(proposed.getUnresolvedSchema())) {\n  useTableChangeApi = true;\n}","typeGuard":"boolean schemaUnchanged(CatalogTable a, CatalogTable b) {\n  return java.util.Objects.equals(a.getUnresolvedSchema(), b.getUnresolvedSchema());\n}","tryCatchPattern":"try { catalog.alterTable(path, proposed, false); }\ncatch (UnsupportedOperationException e) {\n  // fall back to TableChange-based alterTable\ncatalog.alterTable(path, schemaChanges, false);\n}","preventionTips":["Always prefer the TableChange-based alterTable API for schema work","Never mutate a CatalogTable in place and pass it to the legacy alterTable","Check the Flink version's catalog API; the legacy alterTable is properties-only"],"tags":["flink","schema-evolution","deprecated-api","unsupported-operation"],"backgroundTag":"deprecated-api-usage","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}