apache/iceberg · error · UnsupportedOperationException

Cannot specify the 'sort-order' because it's a reserved tabl

Error message

Cannot specify the 'sort-order' because it's a reserved table property. Please use the command 'ALTER TABLE ... WRITE ORDERED BY' to specify write sort-orders.

What it means

During ALTER TABLE, SparkCatalog.alterTable inspects SetProperty changes and rejects attempts to set 'sort-order', which is a reserved internal Iceberg property managed through a dedicated SQL clause, not a plain table property.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/SparkCatalog.java:342

  @Override
  public Table alterTable(Identifier ident, TableChange... changes) throws NoSuchTableException {
    SetProperty setLocation = null;
    SetProperty setSnapshotId = null;
    SetProperty pickSnapshotId = null;
    List<TableChange> propertyChanges = Lists.newArrayList();
    List<TableChange> schemaChanges = Lists.newArrayList();

    for (TableChange change : changes) {
      if (change instanceof SetProperty) {
        SetProperty set = (SetProperty) change;
        if (TableCatalog.PROP_LOCATION.equalsIgnoreCase(set.property())) {
          setLocation = set;
        } else if ("current-snapshot-id".equalsIgnoreCase(set.property())) {
          setSnapshotId = set;
        } else if ("cherry-pick-snapshot-id".equalsIgnoreCase(set.property())) {
          pickSnapshotId = set;
        } else if ("sort-order".equalsIgnoreCase(set.property())) {
          throw new UnsupportedOperationException(
              "Cannot specify the 'sort-order' because it's a reserved table "
                  + "property. Please use the command 'ALTER TABLE ... WRITE ORDERED BY' to specify write sort-orders.");
        } else if ("identifier-fields".equalsIgnoreCase(set.property())) {
          throw new UnsupportedOperationException(
              "Cannot specify the 'identifier-fields' because it's a reserved table property. "
                  + "Please use the command 'ALTER TABLE ... SET IDENTIFIER FIELDS' to specify identifier fields.");
        } else {
          propertyChanges.add(set);
        }
      } else if (change instanceof RemoveProperty) {
        propertyChanges.add(change);
      } else if (change instanceof ColumnChange) {
        schemaChanges.add(change);
      } else {
        throw new UnsupportedOperationException("Cannot apply unknown table change: " + change);
      }
    }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Use ALTER TABLE ... WRITE ORDERED BY to define write sort orders instead of setting the property.
  2. Filter out 'sort-order' (and other reserved properties) when replaying property dumps.
  3. Drop the property assignment from the migration script if sort order is already defined.
  4. Remove the sort order via WRITE ORDERED BY with no columns if clearing is desired — not via property change.

Example fix

// before
spark.sql("ALTER TABLE prod.db.events SET TBLPROPERTIES ('sort-order'='id ASC')");
// after
spark.sql("ALTER TABLE prod.db.events WRITE ORDERED BY id");
Defensive patterns

Strategy: validation

Validate before calling

private static final Set<String> RESERVED = Set.of("location", "current-snapshot-id",
    "cherry-pick-snapshot-id", "sort-order", "identifier-fields");
if (RESERVED.contains(propKey.toLowerCase(Locale.ROOT))) {
  throw new IllegalArgumentException("Reserved property: " + propKey);
}

Try / catch

try {
  spark.sql(alterSql);
} catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("'sort-order'")) {
    throw new IllegalArgumentException("Use ALTER TABLE ... WRITE ORDERED BY for sort orders", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: ALTER TABLE ... SET TBLPROPERTIES ('sort-order' = '...') or a TableChange.setProperty("sort-order", ...) API call.

Common situations: Copying table properties (e.g. via SHOW TBLPROPERTIES dump and re-apply scripts) where the read-only 'sort-order' property gets replayed as a set; hand-written migration scripts serializing all properties.

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/4830aa587ff6d6e8. Report an issue: GitHub.