apache/beam · error · IllegalArgumentException

Unsupported logical type: %s

Error message

Unsupported logical type: %s

What it means

MutationUtils.setBeamValueToMutation() maps Beam Row field values into a Spanner mutation builder, switching on the field's logical type identifier. A logical type with no mapping (ARRAY, MAP, custom logical types, etc.) throws IllegalArgumentException('Unsupported logical type: %s') because Spanner mutations do not accept such values.

Source

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

        // BigDecimal is not nullable
        if (decimal == null) {
          checkNotNull(decimal, "Null decimal at column %s", columnName);
        } else {
          mutationBuilder.set(columnName).to(decimal);
        }
        break;
      case LOGICAL_TYPE:
        Schema.LogicalType<?, ?> logicalType = checkNotNull(fieldType.getLogicalType());
        String identifier = logicalType.getIdentifier();
        if (identifier.equals(MicrosInstant.IDENTIFIER)) {
          @Nullable Instant instant = row.getValue(columnName);
          if (instant == null) {
            mutationBuilder.set(columnName).to((Timestamp) null);
          } else {
            mutationBuilder.set(columnName).to(toSpannerTimestamp(instant));
          }
        } else {
          throw new IllegalArgumentException(
              String.format("Unsupported logical type: %s", identifier));
        }
        break;
      case DATETIME:
        @Nullable ReadableDateTime dateTime = row.getDateTime(columnName);
        if (dateTime == null) {
          mutationBuilder.set(columnName).to(((Timestamp) null));
        } else {
          mutationBuilder
              .set(columnName)
              .to(Timestamp.ofTimeMicroseconds(dateTime.toInstant().getMillis() * 1000L));
        }
        break;
      case BOOLEAN:
        mutationBuilder.set(columnName).to(row.getBoolean(columnName));
        break;
      case STRING:
        mutationBuilder.set(columnName).to(row.getString(columnName));

View on GitHub (pinned to 12126d8942)

Solutions

  1. Map unsupported logical types to supported Spanner types (encode arrays/maps/structs as JSON STRING).
  2. Flatten nested fields into separate scalar columns before the write.
  3. If you own a custom LogicalType, add a case for it (or convert to its base type) before writing.

Example fix

// before
FieldType listField = FieldType.array(FieldType.string) // unsupported in mutation path
// after
FieldType listField = FieldType.STRING // store JSON-encoded array
Defensive patterns

Strategy: validation

Validate before calling

for (Field f : row.getSchema().getFields()) {
  String id = f.getType().getNullableSupplement().getIdentifier();
  if (Set.of("array","map","row","iterable").contains(id.toLowerCase()))
    throw new IllegalArgumentException("flatten field before Spanner write: " + f.getName());
}

Type guard

boolean isMutationWritable(Field f) { return !f.getType().getTypeName().isCollectionType() && !f.getType().getTypeName().isCompositeType() && !f.getType().getTypeName().isMapType(); }

Try / catch

try { mutation = MutationUtils.createMutationFromBeamRows(builder, row); } catch (IllegalArgumentException e) { /* encode field as JSON string and retry */ }

Prevention

When it happens

Trigger: Writing a Beam Row whose schema contains a field with an unmapped logical type (e.g. array, map, row, or a custom LogicalType) through the Spanner sink's createMutationFromBeamRows path.

Common situations: Auto-generated schemas from sources with nested/repeated fields (e.g. BigQuery RECORD, Avro unions) piped into a Spanner write; adding a new custom LogicalType to the schema without extending MutationUtils.

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