{"record":{"id":"f077248713ab567f","repo":"apache/beam","slug":"could-not-find-a-matching-constructor-when-using-field-names","errorCode":null,"errorMessage":"Could not find a matching constructor. When using field names, make sure they are available in the compiled Java class.","messagePattern":"Could not find a matching constructor\\. When using field names, make sure they are available in the compiled Java class\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java","lineNumber":416,"sourceCode":"    Object valueTypeArray = Array.newInstance(arrayComponentType, decodedValues.size());\n    for (int i = 0; i < decodedValues.size(); i++) {\n      Array.set(valueTypeArray, i, arrayComponentType.cast(decodedValues.get(i)));\n    }\n    return (Object[]) valueTypeArray;\n  }\n\n  private Constructor<PTransform<InputT, OutputT>> findMappingConstructor(\n      Constructor<?>[] constructors, JavaClassLookupPayload payload) {\n    Row constructorRow = decodeRow(payload.getConstructorSchema(), payload.getConstructorPayload());\n\n    List<Constructor<?>> mappingConstructors =\n        Arrays.stream(constructors)\n            .filter(c -> c.getParameterCount() == payload.getConstructorSchema().getFieldsCount())\n            .filter(c -> parametersCompatible(c.getParameters(), constructorRow))\n            .collect(Collectors.toList());\n\n    if (mappingConstructors.size() == 0) {\n      throw new RuntimeException(\n          \"Could not find a matching constructor. When using field names, make sure they are \"\n              + \"available in the compiled Java class.\");\n    } else if (mappingConstructors.size() != 1) {\n      throw new RuntimeException(\n          \"Expected to find a single mapping constructor but found \" + mappingConstructors.size());\n    }\n    return (Constructor<PTransform<InputT, OutputT>>) mappingConstructors.get(0);\n  }\n\n  private boolean isConstructorMethodForName(\n      Method method, String nameFromPayload, AllowedClass allowListClass) {\n    for (Annotation annotation : method.getAnnotations()) {\n      if (annotation instanceof MultiLanguageConstructorMethod) {\n        if (nameFromPayload.equals(((MultiLanguageConstructorMethod) annotation).name())) {\n          if (allowListClass.isAllowedConstructorMethod(nameFromPayload)) {\n            return true;\n          } else {\n            throw new RuntimeException(","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java#L398-L434","documentation":"findMappingConstructor filters the target class's constructors by parameter count and by compatibility of each parameter with the constructor Row. If no constructor matches, it throws RuntimeException advising that field names must be present in the compiled class (schema-based field-name matching relies on reflection metadata).","triggerScenarios":"constructor(payload) is called with a constructorSchema whose field count or field types/names do not match any constructor of the loaded class — e.g. parameter names stripped by compilation without -parameters, or schema built for an older class version.","commonSituations":"Compiling without -parameters so name-based matching fails; class version mismatch between the expansion service classpath and the payload schema; overloaded constructors causing count mismatch.","solutions":["Recompile the target class with -parameters so constructor parameter names are retained.","Ensure the expansion service classpath contains the exact class version the payload schema was generated from.","Check getFieldsCount and field types in the payload against the intended constructor signature.","Catch RuntimeException and return a list of available constructors to help debug the mismatch."],"exampleFix":"// before (build.gradle)\ncompileJava { }\n// after\ntasks.withType(JavaCompile) { options.compilerArgs << '-parameters' }","handlingStrategy":"try-catch","validationCode":"long matches = Arrays.stream(Target.class.getConstructors()).filter(c -> c.getParameterCount() == schema.getFieldsCount()).count(); if (matches == 0) throw new IllegalStateException(\"No constructor with arity \" + schema.getFieldsCount());","typeGuard":null,"tryCatchPattern":"try { constructor(payload); } catch (RuntimeException e) { if (e.getMessage().contains(\"Could not find a matching constructor\")) { /* dump class constructors vs payload schema */ } throw e; }","preventionTips":["Compile with -parameters","Keep payload schema generation in lockstep with class versions","Pin the expansion service classpath to the transform jar version","Log candidate constructors on failure"],"tags":["java","reflection","constructor-matching","beam-expansion"],"backgroundTag":"invalid-constructor-argument","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"}