apache/beam · error · IllegalArgumentException

Unknown mutation operation type: %s

Error message

Unknown mutation operation type: %s

What it means

MutationUtils.beamRowToMutationFn() translates the configured mutation operation (INSERT, UPDATE, INSERT_OR_UPDATE, REPLACE, DELETE) into the corresponding Spanner Mutation builder. An operation value outside the known switch cases throws IllegalArgumentException('Unknown mutation operation type: %s').

Source

Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java:80

   * @return function that can convert row to mutation
   */
  public static SerializableFunction<Row, Mutation> beamRowToMutationFn(
      Mutation.Op operation, String table) {
    return row -> {
      switch (operation) {
        case INSERT:
          return MutationUtils.createMutationFromBeamRows(Mutation.newInsertBuilder(table), row);
        case DELETE:
          return Mutation.delete(table, MutationUtils.createKeyFromBeamRow(row));
        case UPDATE:
          return MutationUtils.createMutationFromBeamRows(Mutation.newUpdateBuilder(table), row);
        case REPLACE:
          return MutationUtils.createMutationFromBeamRows(Mutation.newReplaceBuilder(table), row);
        case INSERT_OR_UPDATE:
          return MutationUtils.createMutationFromBeamRows(
              Mutation.newInsertOrUpdateBuilder(table), row);
        default:
          throw new IllegalArgumentException(
              String.format("Unknown mutation operation type: %s", operation));
      }
    };
  }

  private static Key createKeyFromBeamRow(Row row) {
    Key.Builder builder = Key.newBuilder();
    Schema schema = row.getSchema();
    List<String> columns = schema.getFieldNames();
    columns.forEach(
        columnName ->
            setBeamValueToKey(builder, schema.getField(columnName).getType(), columnName, row));
    return builder.build();
  }

  public static Mutation createMutationFromBeamRows(
      Mutation.WriteBuilder mutationBuilder, Row row) {
    Schema schema = row.getSchema();

View on GitHub (pinned to 12126d8942)

Solutions

  1. Set the operation to one of: INSERT, UPDATE, UPSERT (INSERT_OR_UPDATE), REPLACE, DELETE — exact enum name.
  2. Normalize/trim the operation string before building the transform.
  3. Check which enum type is expected by the connector version in use (API names changed across versions).

Example fix

// before
SpannerWrite.withMutationOperation("upsert")
// after
SpannerWrite.withMutationOperation("UPSERT") // or INSERT_OR_UPDATE depending on API version
Defensive patterns

Strategy: validation

Validate before calling

Set<String> OPS = Set.of("INSERT","UPDATE","UPSERT","REPLACE","DELETE");
if (!OPS.contains(operation.trim().toUpperCase())) throw new IllegalArgumentException("unknown operation: " + operation);

Type guard

boolean isKnownOperation(String op) { return java.util.Arrays.stream(MutationOp.values()).anyMatch(m -> m.name().equalsIgnoreCase(op)); }

Try / catch

try { rowToMutationFn = MutationUtils.beamRowToMutationFn(table, op); } catch (IllegalArgumentException e) { /* correct the op enum */ }

Prevention

When it happens

Trigger: Configuring the Spanner write connector with a mutation operation string that is misspelled, lower-cased (e.g. 'insert' vs 'INSERT'), or empty; the enum lookup yields an unexpected value at pipeline construction.

Common situations: Pipeline options/YAML supplying a wrong operation name; upstream refactor renaming the enum; passing a custom string where a MutationOperation enum is expected.

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/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/0330c8086d029443. Report an issue: GitHub.