{"record":{"id":"65cd52482c8a7af6","repo":"apache/beam","slug":"createrowwriter-called-when-schemafactory-is-null-forgot-to","errorCode":null,"errorMessage":"createRowWriter called when schemaFactory is null; forgot to call prepare()?","messagePattern":"createRowWriter called when schemaFactory is null; forgot to call prepare\\(\\)\\?","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/RowWriterFactory.java","lineNumber":138,"sourceCode":"\n    SerializableFunction<AvroWriteRequest<ElementT>, AvroT> getToAvroFn() {\n      return toAvro;\n    }\n\n    @Override\n    OutputType getOutputType() {\n      return OutputType.AvroGenericRecord;\n    }\n\n    @Override\n    BigQueryRowWriter<ElementT> createRowWriter(String tempFilePrefix, DestinationT destination)\n        throws Exception {\n      if (dynamicDestinations == null) {\n        throw new IllegalStateException(\n            \"createRowWriter called when dynamicDestinations is null; forgot to call prepare()?\");\n      }\n      if (schemaFactory == null) {\n        throw new IllegalStateException(\n            \"createRowWriter called when schemaFactory is null; forgot to call prepare()?\");\n      }\n\n      TableSchema tableSchema = dynamicDestinations.getSchema(destination);\n      Schema avroSchema = schemaFactory.apply(tableSchema);\n      return new AvroRowWriter<>(tempFilePrefix, avroSchema, toAvro, writerFactory);\n    }\n\n    @Override\n    String getSourceFormat() {\n      return \"AVRO\";\n    }\n  }\n}\n","sourceCodeStart":120,"sourceCodeEnd":153,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/io/google-cloud-platform/src/main/java/org/apache/beam/sdk/io/gcp/bigquery/RowWriterFactory.java#L120-L153","documentation":"IllegalStateException thrown by RowWriterFactory's anonymous Avro implementation when createRowWriter is invoked but the schemaFactory field is null. schemaFactory is initialized in prepare(); a null value means the factory's setup step was skipped, so the TableSchema-to-Avro-Schema conversion function is unavailable.","triggerScenarios":"createRowWriter called on a RowWriterFactory instance that never had prepare(GenericRecordWriterFactory, DynamicDestinations) invoked, leaving schemaFactory uninitialized even though dynamicDestinations may be set.","commonSituations":"Unit tests invoking createRowWriter directly without prepare; custom pipelines constructing the internal factory by hand; partial refactors where prepare was called with a null schema factory argument.","solutions":["Call prepare(...) with a non-null GenericRecordWriterFactory before creating row writers","If calling prepare manually, verify both arguments (writer factory and dynamic destinations) are non-null","Prefer using BigQueryIO.write() so Beam initializes the factory through its normal DoFn lifecycle"],"exampleFix":"// before\nfactory.prepare(null, dynamicDestinations); // schemaFactory stays null\nfactory.createRowWriter(prefix, destination); // IllegalStateException\n// after\nfactory.prepare(new GenericRecordWriterFactory(tempFilePrefix, useCdcWrites), dynamicDestinations);","handlingStrategy":"validation","validationCode":"if (schemaFactory == null) {\n  throw new IllegalStateException(\"schemaFactory not initialized; call prepare(writerFactory, dynamicDestinations) first\");\n}","typeGuard":"static <E,D> boolean hasSchemaFactory(RowWriterFactory<E,D> f) {\n  try { return f.getClass().getDeclaredField(\"schemaFactory\").get(f) != null; }\n  catch (Exception e) { return false; }\n}","tryCatchPattern":"try {\n  writer = factory.createRowWriter(prefix, destination);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"schemaFactory is null\")) {\n    factory.prepare(recordWriterFactory, dynamicDestinations);\n    writer = factory.createRowWriter(prefix, destination);\n  } else { throw e; }\n}","preventionTips":["Invoke prepare() with a non-null GenericRecordWriterFactory before writing","Never pass null schema factory arguments to prepare()","Drive writes through the public BigQueryIO API rather than internal factories"],"tags":["bigquery","lifecycle","state","gcp"],"backgroundTag":"invalid-state-transition","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"}