{"record":{"id":"afd4d4f19dd2e982","repo":"apache/beam","slug":"record-struct-are-not-primitive-types","errorCode":null,"errorMessage":"RECORD/STRUCT are not primitive types","messagePattern":"RECORD/STRUCT are not primitive types","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryAvroUtils.java","lineNumber":157,"sourceCode":"        if (schema.getScale() != null) {\n          logicalType =\n              LogicalTypes.decimal(schema.getPrecision().intValue(), schema.getScale().intValue());\n        } else if (schema.getPrecision() != null) {\n          logicalType = LogicalTypes.decimal(schema.getPrecision().intValue());\n        } else if (bqType.equals(\"NUMERIC\")) {\n          logicalType = LogicalTypes.decimal(38, 9);\n        } else {\n          // BIGNUMERIC\n          logicalType = LogicalTypes.decimal(77, 38);\n        }\n        return logicalType.addToSchema(SchemaBuilder.builder().bytesType());\n      case \"GEOGRAPHY\":\n      case \"JSON\":\n        return SchemaBuilder.builder().stringBuilder().prop(\"sqlType\", bqType).endString();\n      case \"RECORD\":\n      case \"STRUCT\":\n        // record\n        throw new IllegalArgumentException(\"RECORD/STRUCT are not primitive types\");\n      case \"RANGE\": // TODO add support for range type\n      default:\n        throw new IllegalArgumentException(\"Unknown BigQuery type: \" + bqType);\n    }\n  }\n\n  /**\n   * Formats BigQuery seconds-since-epoch into String matching JSON export. Thread-safe and\n   * immutable.\n   */\n  private static final java.time.format.DateTimeFormatter DATE_TIME_FORMATTER =\n      java.time.format.DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\")\n          .withZone(java.time.ZoneOffset.UTC);\n\n  /** Enum to define the precision of a timestamp since the epoch. */\n  enum TimestampPrecision {\n    MILLISECONDS,\n    MICROSECONDS,","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryAvroUtils.java#L139-L175","documentation":"BigQueryAvroUtils.getPrimitiveType converts a BigQuery standard SQL type name into a primitive Avro Schema.Type. RECORD/STRUCT are composite types, not primitives, so the method explicitly throws IllegalArgumentException instead of silently mis-mapping them.","triggerScenarios":"Calling getPrimitiveType with bqType \"RECORD\" or \"STRUCT\" — i.e. asking for an Avro primitive schema for a nested BigQuery record field, usually via convertField on a TableSchema containing nested fields.","commonSituations":"Building an Avro schema from a BigQuery table schema that contains nested/repeated RECORD fields while treating every column as a primitive; often a bug in custom schema conversion code.","solutions":["Handle RECORD fields recursively via the full convertField/toGenericAvroSchema path, which creates a nested Avro record","Flatten nested BigQuery fields before conversion","Use the library's schema-conversion entry points instead of calling getPrimitiveType directly"],"exampleFix":"// before\nSchema primitive = BigQueryAvroUtils.getPrimitiveType(\"RECORD\");\n// after\nSchema schema = toGenericAvroSchema(\"record\", tableSchema.getFields()); // handles RECORD recursively","handlingStrategy":"try-catch","validationCode":"if (\"RECORD\".equals(field.getType()) || \"STRUCT\".equals(field.getType())) { /* use recursive schema conversion instead */ }","typeGuard":null,"tryCatchPattern":"try { toGenericAvroSchema(name, fields); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"not primitive\")) { /* switch to recursive path */ } else throw e; }","preventionTips":["Never call getPrimitiveType for nested fields","Always use convertField/toGenericAvroSchema end-to-end","Flatten nested BigQuery schemas if only primitives are needed"],"tags":["java","apache-beam","bigquery","avro","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}