apache/iceberg · error · IllegalArgumentException

Unsupported command: ${command}

Error message

Unsupported command: ${command}

What it means

SparkRowLevelOperationBuilder.mode() resolves the row-level operation mode (copy-on-write vs merge-on-read) from table properties for a given command (DELETE, UPDATE, MERGE). If the command is not one of the recognized enum values, it throws IllegalArgumentException('Unsupported command: ...'). This is an internal dispatch guard: the caller must pass a supported Command.

Source

Thrown at spark/v4.2/spark/src/main/java/org/apache/iceberg/spark/source/SparkRowLevelOperationBuilder.java:94

          new SparkPositionDeltaOperation(spark, table, snapshot, branch, info, isolationLevel);
    };
  }

  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);
    }

    return RowLevelOperationMode.fromName(modeName);
  }

  private IsolationLevel isolationLevel(Map<String, String> properties, Command command) {
    String levelName;

    switch (command) {
      case DELETE:
        levelName = properties.getOrDefault(DELETE_ISOLATION_LEVEL, DELETE_ISOLATION_LEVEL_DEFAULT);
        break;
      case UPDATE:
        levelName = properties.getOrDefault(UPDATE_ISOLATION_LEVEL, UPDATE_ISOLATION_LEVEL_DEFAULT);
        break;
      case MERGE:
        levelName = properties.getOrDefault(MERGE_ISOLATION_LEVEL, MERGE_ISOLATION_LEVEL_DEFAULT);
        break;

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check which Command value reached mode(); only DELETE, UPDATE, and MERGE are supported
  2. Upgrade Iceberg Spark runtime to a version that handles the command you issued
  3. If the command comes from custom code, pass one of the supported Command values or extend mode() with a new case
  4. Verify the Spark-Iceberg version pairing matches the docs; mismatched jars can introduce unhandled commands

Example fix

// before
RowLevelOperationMode m = builder.mode(Command.valueOf("REPLACE")); // throws
// after
RowLevelOperationMode m = builder.mode(Command.MERGE); // use a supported command
Defensive patterns

Strategy: validation

Validate before calling

if (command != Command.DELETE && command != Command.UPDATE && command != Command.MERGE) { throw new IllegalArgumentException("Command not supported by Iceberg row-level ops: " + command); }

Try / catch

try { mode = builder.mode(command); } catch (IllegalArgumentException e) { log.error("Unsupported row-level command", e); throw new QueryUnsupportedException(e.getMessage()); }

Prevention

When it happens

Trigger: Calling SparkRowLevelOperationBuilder (or the row-level operation path) with a Command value other than DELETE, UPDATE, or MERGE, e.g. a newly added Spark command not yet handled by the switch in mode().

Common situations: Running a new Spark write command (e.g. REPLACE or a custom operation) against an Iceberg table where the Spark integration hasn't implemented the corresponding mode lookup; internal version skew between Spark extension code and the Command enum.

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/8c6947550f3edc84. Report an issue: GitHub.