{"record":{"id":"4a59c1772a9ad380","repo":"apache/iceberg","slug":"cannot-apply-unknown-table-change-change-4a59c1","errorCode":null,"errorMessage":"Cannot apply unknown table change: ${change}","messagePattern":"Cannot apply unknown table change: (.+?)","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java","lineNumber":169,"sourceCode":"   * Applies a list of Spark table changes to an {@link UpdateProperties} operation.\n   *\n   * @param pendingUpdate an uncommitted UpdateProperties operation to configure\n   * @param changes a list of Spark table changes\n   * @return the UpdateProperties operation configured with the changes\n   */\n  public static UpdateProperties applyPropertyChanges(\n      UpdateProperties pendingUpdate, List<TableChange> changes) {\n    for (TableChange change : changes) {\n      if (change instanceof TableChange.SetProperty) {\n        TableChange.SetProperty set = (TableChange.SetProperty) change;\n        pendingUpdate.set(set.property(), set.value());\n\n      } else if (change instanceof TableChange.RemoveProperty) {\n        TableChange.RemoveProperty remove = (TableChange.RemoveProperty) change;\n        pendingUpdate.remove(remove.property());\n\n      } else {\n        throw new UnsupportedOperationException(\"Cannot apply unknown table change: \" + change);\n      }\n    }\n\n    return pendingUpdate;\n  }\n\n  /**\n   * Applies a list of Spark table changes to an {@link UpdateSchema} operation.\n   *\n   * @param pendingUpdate an uncommitted UpdateSchema operation to configure\n   * @param changes a list of Spark table changes\n   * @return the UpdateSchema operation configured with the changes\n   */\n  public static UpdateSchema applySchemaChanges(\n      UpdateSchema pendingUpdate, List<TableChange> changes) {\n    for (TableChange change : changes) {\n      if (change instanceof TableChange.AddColumn) {\n        apply(pendingUpdate, (TableChange.AddColumn) change);","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/Spark3Util.java#L151-L187","documentation":"Thrown by Spark3Util.applyPropertyChanges when a Spark TableChange is neither SetProperty nor RemoveProperty. Only property changes may be passed to this method; any other change type cannot be applied to a PendingUpdate for properties.","triggerScenarios":"Calling Spark3Util.applyPropertyChanges with a TableChange that is not SetProperty/RemoveProperty, e.g. an AddColumn, DeleteColumn, or UpdateColumnComment leaking into the property-change path.","commonSituations":"Custom catalog or engine integration code that splits an ALTER TABLE change list incorrectly; passing the full change array instead of filtering to property changes first.","solutions":["Filter the change list to instanceof SetProperty/RemoveProperty before calling applyPropertyChanges","Route non-property changes (schema changes) to applySchemaChanges instead","Log/inspect the change object to find which type slipped through"],"exampleFix":"// before\nSpark3Util.applyPropertyChanges(update, changes);\n// after\nList<TableChange> propChanges = Arrays.stream(changes)\n    .filter(c -> c instanceof TableChange.SetProperty || c instanceof TableChange.RemoveProperty)\n    .collect(Collectors.toList());\nSpark3Util.applyPropertyChanges(update, propChanges);","handlingStrategy":"type-guard","validationCode":"boolean allPropertyChanges = Arrays.stream(changes)\n    .allMatch(c -> c instanceof TableChange.SetProperty || c instanceof TableChange.RemoveProperty);","typeGuard":"boolean isPropertyChange(TableChange c) {\n  return c instanceof TableChange.SetProperty || c instanceof TableChange.RemoveProperty;\n}","tryCatchPattern":"try {\n  Spark3Util.applyPropertyChanges(update, changes);\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"Cannot apply unknown table change\")) {\n    // split changes and route each to the right handler\n  }\n}","preventionTips":["Partition the change list by type before dispatching","Log change.getClass().getName() when routing","Cover change routing with unit tests for every TableChange subtype"],"tags":["spark","table-changes","unsupported-operation"],"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"}