apache/beam · error · RuntimeException
Unexpected null for key type: " + fieldDescriptor.getName()
Error message
Unexpected null for key type: " + fieldDescriptor.getName()
What it means
For MAP-typed values in toProtoValue, the key and value FieldTypes are retrieved to convert each entry. A null key type means the map's FieldType lacks key-type metadata; since each BigQuery key/value struct entry needs both converters, the converter throws immediately, naming the proto field.
Solutions
- Rebuild the field with FieldType.map(keyType, valueType).
- Use generic Map<K,V> fields in schema classes so inference records the key type.
- Pre-validate: for each MAP field check getMapKeyType() != null before writing.
- Catch and translate the RuntimeException to a schema-validation error for the offending field.
Example fix
// before FieldType m = FieldType.builder().setType(TypeName.MAP).setMapValueType(FieldType.string()).build(); // after FieldType m = FieldType.map(FieldType.string(), FieldType.string());
Defensive patterns
Strategy: validation
Validate before calling
for (Schema.Field f : schema.getFields()) {
if (f.getType().getTypeName() == Schema.TypeName.MAP && f.getType().getMapKeyType() == null) {
throw new IllegalArgumentException("Field " + f.getName() + " missing map key type");
}
} Type guard
boolean hasMapKeyType(Schema.Field f) {
return f.getType().getTypeName() != Schema.TypeName.MAP || f.getType().getMapKeyType() != null;
} Try / catch
try {
value = toProtoValue(fieldDescriptor, beamFieldType, v);
} catch (RuntimeException e) {
if (e.getMessage().startsWith("Unexpected null for key type")) {
throw new SchemaException("Map field lacks key type: " + e.getMessage());
}
throw e;
} Prevention
- Always create map fields with FieldType.map(k, v)
- Use generic Map<K,V> in record classes
- Run schema completeness checks in CI
When it happens
Trigger: toProtoValue case MAP where beamFieldType.getMapKeyType() returns null - i.e. the FieldType is TypeName.MAP but was not created with a key type (not via FieldType.map(k, v)).
Common situations: Row data carrying Map values whose schema field was assembled without key type; schema inference from raw Map types; schema evolution dropping map metadata.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Unexpected null element type for the map's key on " +…
- Unexpected null element type for the map's value on " +…
- Unexpected null for value type: " +…
- A function must be provided to convert the input type into…
- BigQueryIO.Write transforms cannot be converted to a…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/ca53aa5a6a4ef78e.
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:350
case ROW:
return messageFromBeamRow(fieldDescriptor.getMessageType(), (Row) value, null, -1);
case ARRAY:
case ITERABLE:
Iterable<Object> iterable = (Iterable<Object>) value;
@Nullable FieldType iterableElementType = beamFieldType.getCollectionElementType();
if (iterableElementType == null) {
throw new RuntimeException("Unexpected null element type: " + fieldDescriptor.getName());
}
return StreamSupport.stream(iterable.spliterator(), false)
.map(v -> toProtoValue(fieldDescriptor, iterableElementType, v))
.collect(Collectors.toList());
case MAP:
Map<Object, Object> map = (Map<Object, Object>) value;
@Nullable FieldType keyType = beamFieldType.getMapKeyType();
@Nullable FieldType valueType = beamFieldType.getMapValueType();
if (keyType == null) {
throw new RuntimeException("Unexpected null for key type: " + fieldDescriptor.getName());
}
if (valueType == null) {
throw new RuntimeException(
"Unexpected null for value type: " + fieldDescriptor.getName());
}
return map.entrySet().stream()
.map(
(Map.Entry<Object, Object> entry) ->
mapEntryToProtoValue(
fieldDescriptor.getMessageType(), keyType, valueType, entry))
.collect(Collectors.toList());
default:
return scalarToProtoValue(fieldDescriptor, beamFieldType, value);
}
}
private static DynamicMessage buildTimestampPicosMessage(View on GitHub (pinned to 12126d8942)