{"record":{"id":"8f59268b935ab801","repo":"apache/iceberg","slug":"altering-schema-is-not-supported-in-the-old-altert-8f5926","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":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"flink/v2.2/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/v2.2/flink/src/main/java/org/apache/iceberg/flink/FlinkCatalog.java#L460-L496","documentation":"Apache Iceberg's FlinkCatalog does not support schema changes through Flink's legacy `alterTable(ObjectPath, CatalogTable, boolean)` API. The method compares the unresolved schema of the existing table with the requested one, and any difference throws UnsupportedOperationException. Schema evolution must go through the newer alterTable API that accepts a list of TableChange objects.","triggerScenarios":"Calling catalog.alterTable(tablePath, newCatalogTable, false) where newCatalogTable.getUnresolvedSchema() differs from the existing table's schema (e.g. added, dropped, renamed, or retyped columns).","commonSituations":"Using an old Flink SQL `ALTER TABLE ... ADD/DROP COLUMN` path or a framework that still routes schema DDL through the legacy Catalog API instead of the TableChange-based API.","solutions":["Use the TableChange-based alterTable API: `alterTable(tablePath, List.of(SchemaEvolutionUtil.addSchemaChange(...)), false)` or Flink's `ALTER TABLE ... ADD COLUMN` which maps to it.","Verify that the new CatalogTable differs from the old one only in options/partition-independent properties if you must use the legacy API.","Rewrite the migration code to issue explicit TableChange.addColumn/dropColumn/renameColumn updates."],"exampleFix":"// before\ncatalog.alterTable(tablePath, modifiedCatalogTable, false);\n\n// after\ncatalog.alterTable(tablePath,\n    List.of(Change.addColumn(\"new_col\", Types.LongType.get())),\n    false);","handlingStrategy":"try-catch","validationCode":"// compare schemas before calling legacy alterTable\nif (!Objects.equals(oldCt.getUnresolvedSchema(), newCt.getUnresolvedSchema())) {\n  // switch to TableChange-based alterTable instead\n}","typeGuard":"boolean legacyApiSafe(CatalogTable a, CatalogTable b) {\n  return Objects.equals(a.getUnresolvedSchema(), b.getUnresolvedSchema());\n}","tryCatchPattern":"try {\n  catalog.alterTable(tablePath, ct, false);\n} catch (UnsupportedOperationException e) {\n  // fall back to TableChange-based alterTable for schema evolution\n}","preventionTips":["Prefer the TableChange-based alterTable API for any schema-affecting change","Diff unresolved schemas before calling the legacy API","Keep DDL migrations expressed as explicit TableChange lists"],"tags":["flink","schema-change","unsupported-api"],"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"}