apache/iceberg · error · UnsupportedOperationException

Unsupported table change: setting unique key constraints.

Error message

Unsupported table change: setting unique key constraints.

What it means

Iceberg has no native UNIQUE KEY constraint concept — only identifier fields (primary key). When applyUniqueConstraint receives a UniqueConstraint of type UNIQUE_KEY it throws UnsupportedOperationException because UpdateSchema cannot represent it.

Source

Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/util/FlinkAlterTableUtil.java:253

    if (newPosition instanceof TableChange.First) {
      pendingUpdate.moveFirst(modifyColumnPosition.getOldColumn().getName());
    } else if (newPosition instanceof TableChange.After) {
      TableChange.After after = (TableChange.After) newPosition;
      pendingUpdate.moveAfter(modifyColumnPosition.getOldColumn().getName(), after.column());
    } else {
      throw new UnsupportedOperationException(
          "Cannot apply unknown modify-column-position change: " + modifyColumnPosition);
    }
  }

  private static void applyUniqueConstraint(
      UpdateSchema pendingUpdate, UniqueConstraint constraint) {
    switch (constraint.getType()) {
      case PRIMARY_KEY:
        pendingUpdate.setIdentifierFields(constraint.getColumns());
        break;
      case UNIQUE_KEY:
        throw new UnsupportedOperationException(
            "Unsupported table change: setting unique key constraints.");
      default:
        throw new UnsupportedOperationException(
            "Cannot apply unknown unique constraint: " + constraint.getType().name());
    }
  }
}

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Remove UNIQUE declarations from the DDL; enforce uniqueness upstream or in pipeline logic instead
  2. Express the closest intent as identifier fields (setIdentifierFields) if the columns can act as a primary key
  3. Catch UnsupportedOperationException and document to users that Iceberg/Flink path supports only PRIMARY_KEY constraints

Example fix

// before
ALTER TABLE t ADD UNIQUE (email);
// after
-- enforce uniqueness in pipeline, or:
table.updateSchema().setIdentifierFields("email").commit();
Defensive patterns

Strategy: validation

Validate before calling

boolean hasUniqueKey = changes.stream()
    .filter(c -> c instanceof TableChange.AddUniqueConstraint || c instanceof TableChange.ModifyUniqueConstraint)
    .map(c -> c instanceof TableChange.AddUniqueConstraint
        ? ((TableChange.AddUniqueConstraint) c).getConstraint()
        : ((TableChange.ModifyUniqueConstraint) c).getNewConstraint())
    .anyMatch(u -> u.getType() == ConstraintType.UNIQUE_KEY);
if (hasUniqueKey) throw new IllegalArgumentException("Iceberg supports only PRIMARY_KEY constraints");

Type guard

static boolean isPrimaryKeyConstraint(UniqueConstraint u) { return u.getType() == ConstraintType.PRIMARY_KEY; }

Try / catch

try { FlinkAlterTableUtil.applySchemaChanges(update, changes); }
catch (UnsupportedOperationException e) {
  if (e.getMessage().contains("unique key constraints")) { /* strip UNIQUE DDL and warn user */ }
  throw e;
}

Prevention

When it happens

Trigger: ALTER TABLE ... ADD UNIQUE(...) or a Flink connector config declaring unique keys on an Iceberg table routed to applySchemaChanges → applyUniqueConstraint.

Common situations: Porting warehouse DDL that uses UNIQUE constraints (e.g. from MySQL) to Iceberg; Flink SQL CREATE TABLE with UNIQUE declared; data quality tooling asserting uniqueness via constraint DDL.

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/342f3afd8cbe37b8. Report an issue: GitHub.