apache/beam · error · IllegalArgumentException
Unsupported logical type in key: %s
Error message
Unsupported logical type in key: %s
What it means
MutationUtils.setBeamValueToKey() converts a Beam Row field into a Spanner key value, dispatching on the logical type identifier (strings, integers, floats, booleans, timestamps, dates, bytes...). A logical type not handled for keys throws IllegalArgumentException('Unsupported logical type in key: %s') because Spanner key columns must be scalar types.
Source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java:168
case DOUBLE:
keyBuilder.append(row.getDouble(columnName));
break;
case DECIMAL:
keyBuilder.append(row.getDecimal(columnName));
break;
// TODO: Implement logical date and datetime
case LOGICAL_TYPE:
Schema.LogicalType<?, ?> logicalType = checkNotNull(field.getLogicalType());
String identifier = logicalType.getIdentifier();
if (identifier.equals(MicrosInstant.IDENTIFIER)) {
Instant instant = row.getValue(columnName);
if (instant == null) {
keyBuilder.append((Timestamp) null);
} else {
keyBuilder.append(toSpannerTimestamp(instant));
}
} else {
throw new IllegalArgumentException(
String.format("Unsupported logical type in key: %s", identifier));
}
break;
case DATETIME:
@Nullable ReadableDateTime dateTime = row.getDateTime(columnName);
if (dateTime == null) {
keyBuilder.append((Timestamp) null);
} else {
keyBuilder.append(
Timestamp.ofTimeMicroseconds(dateTime.toInstant().getMillis() * 1_000L));
}
break;
case BOOLEAN:
keyBuilder.append(row.getBoolean(columnName));
break;
case STRING:
keyBuilder.append(row.getString(columnName));
break;View on GitHub (pinned to 12126d8942)
Solutions
- Use only supported scalar key logical types (STRING, INT64, FLOAT64, BOOLEAN, TIMESTAMP, DATE, BYTES, NUMERIC).
- Flatten or drop non-scalar columns from the key mapping.
- Convert exotic logical types to a supported scalar (e.g. encode as STRING) before constructing the key row.
Example fix
// before: key field is an ARRAY logical type
// after: key field is STRING, e.g. StructField.of("id", FieldType.STRING) Defensive patterns
Strategy: validation
Validate before calling
for (Field f : keyRow.getSchema().getFields()) {
if (!Set.of("STRING","INT64","FLOAT64","BOOLEAN","DATETIME","BYTES","logicalType(Numeric)","logicalType(Timestamp)").contains(f.getType().getIdentifier()))
throw new IllegalArgumentException("key field not supported: " + f.getName());
} Type guard
boolean isScalarKeyField(Field f) { return !f.getType().getTypeName().isCollectionType() && !f.getType().getTypeName().isCompositeType(); } Try / catch
try { Key k = MutationUtils.createKeyFromBeamRow(row); } catch (IllegalArgumentException e) { /* flatten key schema */ } Prevention
- Design key mappings with scalar-only fields
- Validate the Beam schema against the Spanner DDL before the write transform
- Avoid auto-plugging inferred schemas into key positions
When it happens
Trigger: Using a Beam schema field with a logical type like ARRAY, MAP, STRUCT, or a custom logical type as part of the key column mapping when building a delete/update mutation via createKeyFromBeamRow.
Common situations: Beam schema auto-inferred from a source containing non-scalar columns, then used directly as the Spanner key mapping; schema drift after a source table change adds a new column type to the key.
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
- Unsupported field type: %s
- Unsupported logical type: %s
- Cannot provide a coder for a Beam Row. Please provide a sche
- Failed to decode Schema due to an error decoding Field proto
- Encountered UNSPECIFIED AtomicType
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/165ebe85b75f40ad.
Report an issue: GitHub.