apache/iceberg · error · IllegalArgumentException

Unsupported operation mode: + mode

Error message

Unsupported operation mode: + mode

What it means

SparkRowLevelOperationBuilder.build() maps the resolved RowLevelOperationMode to either SparkCopyOnWriteOperation or SparkPositionDeltaOperation. Any mode other than COPY_ON_WRITE or MERGE_ON_READ hits the default branch and throws this IllegalArgumentException. There is no third row-level write mode in the Iceberg Spark integration.

Source

Thrown at spark/v4.0/spark/src/main/java/org/apache/iceberg/spark/source/SparkRowLevelOperationBuilder.java:71

  SparkRowLevelOperationBuilder(
      SparkSession spark, Table table, String branch, RowLevelOperationInfo info) {
    this.spark = spark;
    this.table = table;
    this.branch = branch;
    this.info = info;
    this.mode = mode(table.properties(), info.command());
    this.isolationLevel = isolationLevel(table.properties(), info.command());
  }

  @Override
  public RowLevelOperation build() {
    switch (mode) {
      case COPY_ON_WRITE:
        return new SparkCopyOnWriteOperation(spark, table, branch, info, isolationLevel);
      case MERGE_ON_READ:
        return new SparkPositionDeltaOperation(spark, table, branch, info, isolationLevel);
      default:
        throw new IllegalArgumentException("Unsupported operation mode: " + mode);
    }
  }

  private RowLevelOperationMode mode(Map<String, String> properties, Command command) {
    String modeName;

    switch (command) {
      case DELETE:
        modeName = properties.getOrDefault(DELETE_MODE, DELETE_MODE_DEFAULT);
        break;
      case UPDATE:
        modeName = properties.getOrDefault(UPDATE_MODE, UPDATE_MODE_DEFAULT);
        break;
      case MERGE:
        modeName = properties.getOrDefault(MERGE_MODE, MERGE_MODE_DEFAULT);
        break;
      default:
        throw new IllegalArgumentException("Unsupported command: " + command);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Set mode properties to exactly 'copy-on-write' or 'merge-on-read' (case handled by fromName, but no other values are valid).
  2. Inspect table properties with DESCRIBE TABLE / metadata and remove or correct the bad *.*.mode keys.
  3. Remove the invalid property to fall back to the default mode for the command.
  4. Check RowLevelOperationMode.fromName() for accepted names before setting properties.

Example fix

// before
ALTER TABLE t SET TBLPROPERTIES ('write.merge.mode'='mor');
// after
ALTER TABLE t SET TBLPROPERTIES ('write.merge.mode'='merge-on-read');
Defensive patterns

Strategy: validation

Validate before calling

Set<String> valid = Set.of("copy-on-write", "merge-on-read");
String mode = props.getOrDefault("write.merge.mode", "copy-on-write");
if (!valid.contains(mode.toLowerCase(Locale.ROOT))) {
  throw new IllegalArgumentException("Bad write mode: " + mode);
}

Try / catch

try { RowLevelOperation op = builder.build(); } catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Unsupported operation mode")) { fixTableModeProperty(e); }
  else throw e;
}

Prevention

When it happens

Trigger: Table properties such as write.update.mode / write.delete.mode / write.merge.mode are set to an unrecognized string that RowLevelOperationMode.fromName() resolves to a non-standard mode value, then passed to build().

Common situations: Typos in mode properties (e.g. 'copy-on-write ', 'MOR', 'cow'); hand-edited table properties; property values written by other engines or older versions with different names.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/83ad479dbdb067e4. Report an issue: GitHub.