{"record":{"id":"925aeab81fc80909","repo":"apache/beam","slug":"unexpectedly-null-logical-type-beamfieldtype","errorCode":null,"errorMessage":"Unexpectedly null logical type \" + beamFieldType","messagePattern":"Unexpectedly null logical type \" \\+ beamFieldType","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java","lineNumber":389,"sourceCode":"    long picoseconds = instant.getNano() * 1000L; // nanos → picos\n\n    return DynamicMessage.newBuilder(timestampPicosDescriptor)\n        .setField(\n            Preconditions.checkNotNull(timestampPicosDescriptor.findFieldByName(\"seconds\")),\n            seconds)\n        .setField(\n            Preconditions.checkNotNull(timestampPicosDescriptor.findFieldByName(\"picoseconds\")),\n            picoseconds)\n        .build();\n  }\n\n  @VisibleForTesting\n  static Object scalarToProtoValue(\n      @Nullable FieldDescriptor fieldDescriptor, FieldType beamFieldType, Object value) {\n    if (beamFieldType.getTypeName() == TypeName.LOGICAL_TYPE) {\n      @Nullable LogicalType<?, ?> logicalType = beamFieldType.getLogicalType();\n      if (logicalType == null) {\n        throw new RuntimeException(\"Unexpectedly null logical type \" + beamFieldType);\n      }\n      if (logicalType.getIdentifier().equals(Timestamp.IDENTIFIER)) {\n        Instant instant = (Instant) value;\n        Descriptor timestampPicosDescriptor =\n            Preconditions.checkNotNull(fieldDescriptor).getMessageType();\n        return buildTimestampPicosMessage(timestampPicosDescriptor, instant);\n      }\n      @Nullable\n      BiFunction<LogicalType<?, ?>, Object, Object> logicalTypeEncoder =\n          LOGICAL_TYPE_ENCODERS.get(logicalType.getIdentifier());\n      if (logicalTypeEncoder == null) {\n        throw new RuntimeException(\"Unsupported logical type \" + logicalType.getIdentifier());\n      }\n      return logicalTypeEncoder.apply(logicalType, value);\n    } else {\n      @Nullable\n      Function<Object, Object> encoder = PRIMITIVE_ENCODERS.get(beamFieldType.getTypeName());\n      if (encoder == null) {","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BeamRowToStorageApiProto.java#L371-L407","documentation":"scalarToProtoValue handles primitive and logical-type scalars. For a LOGICAL_TYPE field it calls beamFieldType.getLogicalType(); if that returns null the FieldType claims a logical type but carries no LogicalType instance (identifier/argument metadata missing), making value conversion undefined, so it throws.","triggerScenarios":"scalarToProtoValue (via toProtoValue) receiving a FieldType whose getTypeName() == TypeName.LOGICAL_TYPE but whose getLogicalType() is null - e.g. a FieldType built with setType(TypeName.LOGICAL_TYPE) directly instead of FieldType.logicalType(...), or one reconstructed from a lossy serialization.","commonSituations":"Hand-built logical-type FieldTypes bypassing the factory method; schemas copied between Beam versions where logical type metadata is incompatible; reflection-based schema assembly.","solutions":["Create logical-type fields via FieldType.logicalType(LogicalType) so the LogicalType instance is attached.","Attach the logical type with withLogicalType() on an existing FieldType rather than setting the raw TypeName.","Pre-validate: for each LOGICAL_TYPE field assert getLogicalType() != null before writing.","Regenerate the schema from the record class instead of reusing a serialized one."],"exampleFix":"// before\nFieldType lt = FieldType.builder().setType(TypeName.LOGICAL_TYPE).build();\n// after\nFieldType lt = FieldType.logicalType(Timestamp.of(TimeUnit.NANOSECONDS));","handlingStrategy":"validation","validationCode":"for (Schema.Field f : schema.getFields()) {\n  if (f.getType().getTypeName() == Schema.TypeName.LOGICAL_TYPE && f.getType().getLogicalType() == null) {\n    throw new IllegalArgumentException(\"Field \" + f.getName() + \" has LOGICAL_TYPE without a LogicalType instance\");\n  }\n}","typeGuard":"boolean hasLogicalTypeInstance(Schema.Field f) {\n  return f.getType().getTypeName() != Schema.TypeName.LOGICAL_TYPE || f.getType().getLogicalType() != null;\n}","tryCatchPattern":"try {\n  value = toProtoValue(fieldDescriptor, beamFieldType, v);\n} catch (RuntimeException e) {\n  if (e.getMessage().startsWith(\"Unexpectedly null logical type\")) {\n    throw new SchemaException(\"Logical type metadata missing on field: \" + e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Create logical-type fields only via FieldType.logicalType(...)","Never set TypeName.LOGICAL_TYPE directly on a builder","Rebuild schemas from record classes rather than serializing/deserializing them across versions"],"tags":["java","apache-beam","bigquery","logical-type"],"backgroundTag":"internal-invariant-violation","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"}