{"record":{"id":"165ebe85b75f40ad","repo":"apache/beam","slug":"unsupported-logical-type-in-key-s","errorCode":null,"errorMessage":"Unsupported logical type in key: %s","messagePattern":"Unsupported logical type in key: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java","lineNumber":168,"sourceCode":"      case DOUBLE:\n        keyBuilder.append(row.getDouble(columnName));\n        break;\n      case DECIMAL:\n        keyBuilder.append(row.getDecimal(columnName));\n        break;\n        // TODO: Implement logical date and datetime\n      case LOGICAL_TYPE:\n        Schema.LogicalType<?, ?> logicalType = checkNotNull(field.getLogicalType());\n        String identifier = logicalType.getIdentifier();\n        if (identifier.equals(MicrosInstant.IDENTIFIER)) {\n          Instant instant = row.getValue(columnName);\n          if (instant == null) {\n            keyBuilder.append((Timestamp) null);\n          } else {\n            keyBuilder.append(toSpannerTimestamp(instant));\n          }\n        } else {\n          throw new IllegalArgumentException(\n              String.format(\"Unsupported logical type in key: %s\", identifier));\n        }\n        break;\n      case DATETIME:\n        @Nullable ReadableDateTime dateTime = row.getDateTime(columnName);\n        if (dateTime == null) {\n          keyBuilder.append((Timestamp) null);\n        } else {\n          keyBuilder.append(\n              Timestamp.ofTimeMicroseconds(dateTime.toInstant().getMillis() * 1_000L));\n        }\n        break;\n      case BOOLEAN:\n        keyBuilder.append(row.getBoolean(columnName));\n        break;\n      case STRING:\n        keyBuilder.append(row.getString(columnName));\n        break;","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/spanner/MutationUtils.java#L150-L186","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: key field is an ARRAY logical type\n// after: key field is STRING, e.g. StructField.of(\"id\", FieldType.STRING)","handlingStrategy":"validation","validationCode":"for (Field f : keyRow.getSchema().getFields()) {\n  if (!Set.of(\"STRING\",\"INT64\",\"FLOAT64\",\"BOOLEAN\",\"DATETIME\",\"BYTES\",\"logicalType(Numeric)\",\"logicalType(Timestamp)\").contains(f.getType().getIdentifier()))\n    throw new IllegalArgumentException(\"key field not supported: \" + f.getName());\n}","typeGuard":"boolean isScalarKeyField(Field f) { return !f.getType().getTypeName().isCollectionType() && !f.getType().getTypeName().isCompositeType(); }","tryCatchPattern":"try { Key k = MutationUtils.createKeyFromBeamRow(row); } catch (IllegalArgumentException e) { /* flatten key schema */ }","preventionTips":["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"],"tags":["java","apache-beam","spanner","schema"],"backgroundTag":"unsupported-operation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}