apache/beam · error · RuntimeException
Unexpected null logical type " + field.getType()
Error message
Unexpected null logical type " + field.getType()
What it means
fieldDescriptorFromBeamField, for LOGICAL_TYPE fields, calls field.getType().getLogicalType() and throws "Unexpected null logical type <field type>" when null. A LOGICAL_TYPE FieldType must carry a LogicalType instance to map to a BigQuery TableFieldSchema.Type; a null result leaves the conversion impossible.
Solutions
- Attach the logical type: Schema.FieldType.logicalType(newyourLogicalType()) so getLogicalType() is non-null
- If the underlying value is a timestamp, use Schema.FieldType.DATETIME or the Beam Timestamp logical type instead
- Verify schemas aren't losing their logical-type argument during serialization between pipeline stages
- Inspect the printed field.getType() in the message to see which field is malformed
Example fix
// before Schema.FieldType lt = Schema.FieldType.of(TypeName.LOGICAL_TYPE); // after Schema.FieldType lt = Schema.FieldType.logicalType(new SqlTypes.LocalTimestamp());
Defensive patterns
Strategy: validation
Validate before calling
// Java
for (Schema.Field f : beamSchema.getFields()) {
if (f.getType().getTypeName() == TypeName.LOGICAL_TYPE && f.getType().getLogicalType() == null) {
throw new IllegalStateException("LOGICAL_TYPE field without logical type: " + f.getName());
}
} Type guard
// Java
LogicalType<?, ?> lt = fieldType.getLogicalType();
if (lt != null) { /* safe to map to TableFieldSchema.Type */ } Try / catch
// Java
try {
descriptor = BeamRowToStorageApiProto.protoTableSchemaFromBeamSchema(beamSchema);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Unexpected null logical type")) {
// attach the LogicalType instance to the field
}
throw e;
} Prevention
- Construct logical-type fields only via Schema.FieldType.logicalType(instance)
- Use built-in logical types (SqlTypes, Timestamp) rather than bare LOGICAL_TYPE TypeNames
- Validate schemas after any serialization/deserialization round trip
When it happens
Trigger: A Beam Schema field declared with TypeName.LOGICAL_TYPE but constructed without a LogicalType argument (e.g. Schema.FieldType.logicalType(null) or bare logical type name), then written to BigQuery Storage API
Common situations: Custom logical-type handling code, schemas serialized/deserialized across job versions losing the logical-type argument, or manual FieldType construction.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Cannot cast to a compatible object to build ByteString.
- Cannot convert Beam logical type: to BigQuery type.
- Reserved field name " + field.getName() + " in user schema.
- Unexpected null element type on " + field.getName()
- Unexpected null schema!
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/04b93aa1cb1e5b83.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java:249
field.getName());
Preconditions.checkState(
!(containedTypeName.isCollectionType() || containedTypeName.isMapType()),
"Nested container types are not supported by BigQuery. Field %s contains a type %s",
field.getName(),
containedTypeName.name());
TableFieldSchema elementFieldSchema =
fieldDescriptorFromBeamField(Field.of(field.getName(), elementType));
builder = builder.setType(elementFieldSchema.getType());
if (elementFieldSchema.hasTimestampPrecision()) {
builder = builder.setTimestampPrecision(elementFieldSchema.getTimestampPrecision());
}
builder.addAllFields(elementFieldSchema.getFieldsList());
builder = builder.setMode(TableFieldSchema.Mode.REPEATED);
break;
case LOGICAL_TYPE:
@Nullable LogicalType<?, ?> logicalType = field.getType().getLogicalType();
if (logicalType == null) {
throw new RuntimeException("Unexpected null logical type " + field.getType());
}
@Nullable TableFieldSchema.Type type;
if (logicalType.getIdentifier().equals(Timestamp.IDENTIFIER)) {
int precision =
Preconditions.checkNotNull(
logicalType.getArgument(),
"Expected logical type argument for timestamp precision.");
if (precision != 9) {
throw new RuntimeException(
"Unsupported precision for Timestamp logical type " + precision);
}
// Map Timestamp.NANOS logical type to BigQuery TIMESTAMP(12) for nanosecond precision
type = TableFieldSchema.Type.TIMESTAMP;
builder.setTimestampPrecision(Int64Value.newBuilder().setValue(12L).build());
} else {
type = LOGICAL_TYPES.get(logicalType.getIdentifier());
if (type == null) {
throw new RuntimeException("Unsupported logical type " + field.getType());View on GitHub (pinned to 12126d8942)