apache/beam · error · IllegalStateException
Unsupported logical type:
Error message
Unsupported logical type:
What it means
CellValueParser.getCellValue converts a Bigtable cell ByteString back into a Java object based on the declared Beam Schema FieldType. LOGICAL_TYPE fields are not supported for parsing: the parser immediately throws an IllegalStateException naming the logical type's identifier. The library can only decode primitive (STRING/BYTES/numeric/BOOLEAN...) cell values.
Solutions
- Change the schema field type to a primitive type (STRING or BYTES) and convert the logical value in user code after reading.
- If the logical type is a PassThroughLogicalType, read using its getBaseType() instead of the logical type.
- Implement a custom mapper/parse function on BigtableIO.read() instead of relying on schema auto-mapping.
Example fix
// before
Schema.FieldType fieldType = Schema.FieldType.logicalType(MyLogicalType.of());
// after
Schema.FieldType fieldType = Schema.FieldType.STRING;
Row row = ...; // parse MyLogicalType.from(row.getString("col")) in user code Defensive patterns
Strategy: validation
Validate before calling
for (Schema.Field f : schema.getFields()) {
if (f.getType().getTypeName() == Schema.TypeName.LOGICAL_TYPE) {
throw new IllegalArgumentException(
"Field " + f.getName() + " uses logical type " + f.getType().getLogicalType().getIdentifier()
+ " which BigtableIO cannot parse; use a primitive type.");
}
} Type guard
static boolean isParsableCellType(Schema.FieldType t) {
return t.getTypeName() != Schema.TypeName.LOGICAL_TYPE;
} Prevention
- Keep Bigtable read schemas limited to primitive field types.
- Convert logical values (dates, enums) to strings/bytes in user code after reading.
- Unit-test schema round-trips against BigtableIO before deploying.
When it happens
Trigger: Reading Bigtable rows into a Beam schema whose field type is a logical type (e.g. beam:logical_type:javasdk:...) instead of a primitive type, causing the switch in getCellValue to hit case LOGICAL_TYPE and throw.
Common situations: Defining a BigtableIO read with a custom Schema that uses a LogicalType (like a custom enum or datetime logical type) for a column family cell; users assume round-tripping works because writing may pass through via PassThroughLogicalType.
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
- columnsMapping ' ' does not fit to schema field names
- Failed to extract logical type
- key field type should be STRING but was
- Logical types don't match and cannot be merged…
- Most ( ) and least ( ) significant bits value shouldn't be…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4ce7dffe4c5ec26e.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigtable/CellValueParser.java:70
return Ints.fromByteArray(cellValue.toByteArray());
case INT64:
checkArgument(valueSize == 8, message("Int64", 8));
return Longs.fromByteArray(cellValue.toByteArray());
case FLOAT:
checkArgument(valueSize == 4, message("Float", 4));
return Float.intBitsToFloat(Ints.fromByteArray(cellValue.toByteArray()));
case DOUBLE:
checkArgument(valueSize == 8, message("Double", 8));
return Double.longBitsToDouble(Longs.fromByteArray(cellValue.toByteArray()));
case DATETIME:
return DateTime.parse(cellValue.toStringUtf8());
case STRING:
return cellValue.toStringUtf8();
case BYTES:
return cellValue.toByteArray();
case LOGICAL_TYPE:
String identifier = checkArgumentNotNull(type.getLogicalType()).getIdentifier();
throw new IllegalStateException("Unsupported logical type: " + identifier);
default:
throw new IllegalArgumentException(
String.format("Unsupported cell value type '%s'.", type.getTypeName()));
}
}
ByteString valueToByteString(Object value, Schema.FieldType type) {
switch (type.getTypeName()) {
case BOOLEAN:
return byteString(((Boolean) value) ? new byte[] {1} : new byte[] {0});
case FLOAT:
return byteString(Ints.toByteArray(Float.floatToIntBits((Float) value)));
case DOUBLE:
return byteString(Longs.toByteArray(Double.doubleToLongBits((Double) value)));
case BYTE:
return byteString(new byte[] {(Byte) value});
case INT16:
return byteString(Shorts.toByteArray((Short) value));View on GitHub (pinned to 12126d8942)