apache/beam · error · RuntimeException
No matching constructor found for class
Error message
No matching constructor found for class ${clazz} What it means
AvroByteBuddyUtils generates fast object constructors for Avro SpecificRecords via ByteBuddy. It expects the record class to have a constructor whose parameter count equals the schema's field count; if none is found it throws RuntimeException.
Solutions
- Use an Avro-generated SpecificRecord class matching the schema (regenerate with avro-maven-plugin)
- Ensure the schema passed matches the class's actual fields
- Fall back to reflection-based conversion instead of ByteBuddy (set the appropriate AvroUtils option)
Example fix
// before AvroByteBuddyUtils.getTypeCreator(myPlainPojoClass, schema); // after (regenerate class from schema first) mvn generate-sources // avro-maven-plugin produces MyRecord with matching constructor AvroByteBuddyUtils.getTypeCreator(MyRecord.class, schema);
Defensive patterns
Strategy: validation
Validate before calling
long ctors = Arrays.stream(clazz.getConstructors())
.filter(c -> c.getParameterCount() == schema.getFieldCount()).count();
if (ctors == 0) throw new IllegalStateException(clazz + " has no constructor matching " + schema.getFieldCount() + " fields"); Type guard
static boolean hasMatchingConstructor(Class<?> c, Schema s) {
return Arrays.stream(c.getConstructors())
.anyMatch(k -> k.getParameterCount() == s.getFields().size());
} Try / catch
try { getCreator(clazz, schema); } catch (RuntimeException e) { /* fall back to reflection-based conversion */ } Prevention
- Only pass Avro-generated SpecificRecord classes to ByteBuddy converters
- Regenerate classes whenever the schema changes
- Verify schema field count matches class constructor arity in tests
When it happens
Trigger: Calling AvroByteBuddyUtils.getCreator (used by AvroSchemaUtil / converters) with a class whose declared constructors don't match the schema field count — e.g. non-SpecificRecord classes, manually edited records, or a schema whose fieldCount disagrees with the generated class.
Common situations: Using AvroSchemaUtil.toJavaBean-style conversion with plain POJOs instead of Avro-generated classes, stale generated classes after schema evolution, or hand-written classes implementing SpecificRecord.
Related errors
- Unable to generate
- Unable to generate a getter for class
- A schema must be provided when writing to BigQuery using…
- An explicit schema is required to write non-schema'd…
- Avro only supports maps with string keys
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/e74cb494339f19a9.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/extensions/avro/src/main/java/org/apache/beam/sdk/extensions/avro/schemas/utils/AvroByteBuddyUtils.java:76
Maps.newConcurrentMap();
static <T extends SpecificRecord> SchemaUserTypeCreator getCreator(
Class<T> clazz, Schema schema) {
return CACHED_CREATORS.computeIfAbsent(
ClassWithSchema.create(clazz, schema), c -> createCreator(clazz, schema));
}
private static <T> SchemaUserTypeCreator createCreator(Class<T> clazz, Schema schema) {
Constructor baseConstructor = null;
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// TODO: This assumes that Avro only generates one constructor with this many fields.
if (constructor.getParameterCount() == schema.getFieldCount()) {
baseConstructor = constructor;
}
}
if (baseConstructor == null) {
throw new RuntimeException("No matching constructor found for class " + clazz);
}
// Generate a method call to create and invoke the SpecificRecord's constructor. .
MethodCall construct = MethodCall.construct(baseConstructor);
for (int i = 0; i < baseConstructor.getParameterTypes().length; ++i) {
Class<?> baseType = baseConstructor.getParameterTypes()[i];
construct = construct.with(readAndConvertParameter(baseType, i), baseType);
}
try {
DynamicType.Builder<SchemaUserTypeCreator> builder =
BYTE_BUDDY
.with(new InjectPackageStrategy(clazz))
.subclass(SchemaUserTypeCreator.class)
.method(ElementMatchers.named("create"))
.intercept(construct);
return builderView on GitHub (pinned to 12126d8942)