{"record":{"id":"92a94bfd8bb4d0ff","repo":"apache/beam","slug":"dynamicmessage-is-not-supported","errorCode":null,"errorMessage":"DynamicMessage is not supported.","messagePattern":"DynamicMessage is not supported\\.","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/BigQueryIO.java","lineNumber":2629,"sourceCode":"    return BigQueryIO.<GenericRecord>write()\n        .withAvroFormatFunction(GENERIC_RECORD_IDENTITY_FORMATTER);\n  }\n\n  /**\n   * A {@link PTransform} that writes a {@link PCollection} containing protocol buffer objects to a\n   * BigQuery table. If using one of the storage-api write methods, these protocol buffers must\n   * match the schema of the table.\n   *\n   * <p>If a Schema is provided using {@link Write#withSchema}, that schema will be used for\n   * creating the table if necessary. If no schema is provided, one will be inferred from the\n   * protocol buffer's descriptor. Note that inferring a schema from the protocol buffer may not\n   * always provide the intended schema as multiple BigQuery types can map to the same protocol\n   * buffer type. For example, a protocol buffer field of type INT64 may be an INT64 BigQuery type,\n   * but it might also represent a TIME, DATETIME, or a TIMESTAMP type.\n   */\n  public static <T extends Message> Write<T> writeProtos(Class<T> protoMessageClass) {\n    if (DynamicMessage.class.equals(protoMessageClass)) {\n      throw new IllegalArgumentException(\"DynamicMessage is not supported.\");\n    }\n    try {\n      return BigQueryIO.<T>write().toBuilder()\n          .setFormatFunction(FormatProto.fromClass(protoMessageClass))\n          .build()\n          .withWriteProtosClass(protoMessageClass);\n    } catch (Exception e) {\n      throw new RuntimeException(e);\n    }\n  }\n\n  abstract static class TableRowFormatFunction<T>\n      implements SerializableBiFunction<\n          TableRowToStorageApiProto.@Nullable SchemaInformation, T, TableRow> {\n    static <T> TableRowFormatFunction<T> fromSerializableFunction(\n        SerializableFunction<T, TableRow> serializableFunction) {\n      return new TableRowFormatFunction<T>() {\n        @Override","sourceCodeStart":2611,"sourceCodeEnd":2647,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/BigQueryIO.java#L2611-L2647","documentation":"BigQueryIO.writeProtos(Class) refuses DynamicMessage as the proto message class. DynamicMessage carries no compile-time schema, so Beam cannot reliably map protobuf field types to BigQuery types (e.g. INT64 could be INT64, TIME, DATETIME, or TIMESTAMP). The library throws IllegalArgumentException immediately to force callers to use a concrete generated protobuf message class.","triggerScenarios":"Calling BigQueryIO.writeProtos(DynamicMessage.class), or passing a variable/class reference that resolves to DynamicMessage.class instead of a generated protobuf message class.","commonSituations":"Developers building pipelines where the proto schema is only known at runtime (e.g. reading descriptor sets or Confluent Schema Registry) and mistakenly use DynamicMessage with writeProtos instead of the typed write() path with a custom format function.","solutions":["Use a concrete generated protobuf class (e.g. MyProto.MyMessage.class) with BigQueryIO.writeProtos and supply the schema explicitly via withSchema/fromClass.","If the schema is genuinely dynamic, use BigQueryIO.write() with withFormatFunction(FormatProto.fromDynamicMessage(...)) or a custom function converting the DynamicMessage to a TableRow, and set the schema explicitly with withJsonSchema.","Never pass DynamicMessage.class; add an upfront check that the class does not equal DynamicMessage.class."],"exampleFix":"// before\nWrite<DynamicMessage> w = BigQueryIO.writeProtos(DynamicMessage.class);\n// after\nWrite<MyProto.Event> w = BigQueryIO.writeProtos(MyProto.Event.class)\n    .withSchema(MySchemaUtil.forProto(MyProto.Event.class));","handlingStrategy":"validation","validationCode":"if (DynamicMessage.class.equals(protoMessageClass)) {\n  throw new IllegalArgumentException(\"Use a generated protobuf class with writeProtos, not DynamicMessage.class\");\n}\nWrite<T> w = BigQueryIO.writeProtos(protoMessageClass);","typeGuard":"static <T extends Message> boolean isSupportedProtoClass(Class<T> c) {\n  return c != null && !DynamicMessage.class.equals(c) && Message.class.isAssignableFrom(c);\n}","tryCatchPattern":"try {\n  write = BigQueryIO.writeProtos(protoClass);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"DynamicMessage is not supported\")) {\n    write = BigQueryIO.<T>write().withFormatFunction(formatFromDynamicMessage);\n  } else { throw e; }\n}","preventionTips":["Always pass compile-time generated protobuf classes to writeProtos.","For runtime schemas, use BigQueryIO.write() with a custom format function plus an explicit withJsonSchema.","Add a unit test that builds the write transform so misconfiguration fails in CI, not at runtime."],"tags":["java","bigquery","apache-beam","protobuf","invalid-argument"],"backgroundTag":"invalid-argument-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}