{"record":{"id":"31290471b9e56b04","repo":"apache/beam","slug":"nested-row-missing-row-schema","errorCode":null,"errorMessage":"Nested ROW missing row schema","messagePattern":"Nested ROW missing row schema","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java","lineNumber":1078,"sourceCode":"          switch (options.getTruncateTimestamps()) {\n            case TRUNCATE:\n              return truncateToMillis(avroValue);\n            case REJECT:\n              return safeToMillis(avroValue);\n            default:\n              throw new IllegalArgumentException(\n                  String.format(\n                      \"Unknown timestamp truncation option: %s\", options.getTruncateTimestamps()));\n          }\n        } else if (logicalType instanceof PassThroughLogicalType) {\n          return convertAvroFormat(logicalType.getBaseType(), avroValue, options);\n        } else {\n          throw new RuntimeException(\"Unknown logical type \" + identifier);\n        }\n      case ROW:\n        Schema rowSchema = beamFieldType.getRowSchema();\n        if (rowSchema == null) {\n          throw new IllegalArgumentException(\"Nested ROW missing row schema\");\n        }\n        GenericData.Record record = (GenericData.Record) avroValue;\n        return toBeamRow(record, rowSchema, options);\n      case MAP:\n        return convertAvroRecordToMap(beamFieldType, avroValue, options);\n      default:\n        throw new RuntimeException(\n            \"Does not support converting unknown type value: \" + beamFieldTypeName);\n    }\n  }\n\n  private static ReadableInstant safeToMillis(Object value) {\n    long subMilliPrecision = ((long) value) % 1000;\n    if (subMilliPrecision != 0) {\n      throw new IllegalArgumentException(\n          String.format(\n              \"BigQuery data contained value %s with sub-millisecond precision, which Beam does\"\n                  + \" not currently support.\"","sourceCodeStart":1060,"sourceCodeEnd":1096,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryUtils.java#L1060-L1096","documentation":"Thrown as IllegalArgumentException when convertAvroFormat handles a Beam ROW-typed field whose FieldType has no row schema attached. To recursively convert a nested Avro record into a Beam Row, the field type must carry its nested Schema; a missing schema is treated as an invalid/incomplete schema definition. This indicates the Beam schema was built incorrectly rather than bad data.","triggerScenarios":"A Beam schema field of type ROW was created via FieldType.row() without .getRowSchema()/withRowSchema, or the row schema was lost during schema serialization/deserialization, then BigQueryIO avro conversion recursed into that field.","commonSituations":"Hand-constructed FieldType.row() calls; schemas built dynamically/reflection-based where nested types weren't registered; schema transport through formats that drop nested schema metadata.","solutions":["Attach the nested schema: use FieldType.row(Schema) or .withRowSchema(nestedSchema) when building the field type.","Verify the top-level Schema was built with Schema.builder() so nested ROW fields get their schemas populated.","If schemas cross a serialization boundary, ensure the row schema field is preserved (it is part of FieldType serialization).","Log/inspect beamFieldType with Schema coder display to find which nested field lacks its schema."],"exampleFix":"// before\nFieldType nested = FieldType.row(); // no schema\n// after\nFieldType nested = FieldType.row(nestedSchema);","handlingStrategy":"validation","validationCode":"// Java: verify every ROW field has a row schema before conversion\nfor (Field f : schema.getFields()) {\n  if (f.getType().getTypeName() == TypeName.ROW && f.getType().getRowSchema() == null) {\n    throw new IllegalStateException(\"Field \" + f.getName() + \" is ROW but has no row schema\");\n  }\n}","typeGuard":"// Java\nstatic boolean hasRowSchema(FieldType t) {\n  return t.getTypeName() != TypeName.ROW || t.getRowSchema() != null;\n}","tryCatchPattern":"try { return convertAvroFormat(field, value, opts); } catch (IllegalArgumentException e) { if (\"Nested ROW missing row schema\".equals(e.getMessage())) { throw new SchemaConfigurationException(field.getName()); } throw e; }","preventionTips":["Always construct ROW fields with FieldType.row(Schema) rather than bare FieldType.row().","Build schemas with Schema.builder()/reflection helpers so nested schemas are populated automatically.","Unit-test schema round-trips through your coder/serialization path to catch dropped nested schemas."],"tags":["java","beam","bigquery","schema","row"],"backgroundTag":"missing-required-config-field","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"}