{"record":{"id":"8689fbbbddca2a73","repo":"apache/beam","slug":"expected-to-find-exactly-one-matching-method-in-transform","errorCode":null,"errorMessage":"Expected to find exactly one matching method in transform  for BuilderMethod but found ","messagePattern":"Expected to find exactly one matching method in transform  for BuilderMethod but found ","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java","lineNumber":232,"sourceCode":"    Row builderMethodRow = decodeRow(builderMethod.getSchema(), builderMethod.getPayload());\n\n    List<Method> matchingMethods =\n        Arrays.stream(transform.getClass().getMethods())\n            .filter(m -> isBuilderMethodForName(m, builderMethod.getName(), allowListClass))\n            .filter(m -> parametersCompatible(m.getParameters(), builderMethodRow))\n            .filter(m -> PTransform.class.isAssignableFrom(m.getReturnType()))\n            .collect(Collectors.toList());\n\n    if (matchingMethods.size() == 0) {\n      throw new RuntimeException(\n          \"Could not find a matching method in transform \"\n              + transform\n              + \" for BuilderMethod\"\n              + builderMethod\n              + \". When using field names, make sure they are available in the compiled\"\n              + \" Java class.\");\n    } else if (matchingMethods.size() > 1) {\n      throw new RuntimeException(\n          \"Expected to find exactly one matching method in transform \"\n              + transform\n              + \" for BuilderMethod\"\n              + builderMethod\n              + \" but found \"\n              + matchingMethods.size());\n    }\n    return matchingMethods.get(0);\n  }\n\n  private static boolean isPrimitiveOrWrapperOrString(java.lang.Class<?> type) {\n    return ClassUtils.isPrimitiveOrWrapper(type) || type == String.class;\n  }\n\n  private Schema getParameterSchema(Class<?> parameterClass) {\n    Schema parameterSchema;\n    try {\n      parameterSchema = SCHEMA_REGISTRY.getSchema(parameterClass);","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java#L214-L250","documentation":"The name/parameter filtering found more than one candidate builder method matching the requested BuilderMethod, so resolution is ambiguous and the service refuses to pick one. Expansion requires an exact, unique match.","triggerScenarios":"A transform exposes overloaded builder methods (same field name, different parameter types/schemas) that all appear compatible with the payload row; withX and field-name convention both resolving to multiple candidates.","commonSituations":"Adding an overload like withTags(List<String>) alongside withTags(String[]) making the payload ambiguous; payload schema generic enough to match several overloads.","solutions":["Remove or rename the ambiguous overload in the transform so exactly one builder method matches the payload schema.","Make the payload parameter schema more specific (correct array vs scalar types) so only one overload is compatible.","Use an explicit @MultiLanguageBuilderMethod-named method that is unique for the requested operation."],"exampleFix":"// before\npublic MyTransform withTags(List<String> tags) {...}\npublic MyTransform withTags(String[] tags) {...}\n// after\npublic MyTransform withTags(List<String> tags) {...}  // single overload","handlingStrategy":"validation","validationCode":"long matches = Stream.of(transformClass.getMethods())\n    .filter(m -> methodMatchesName(m, name))\n    .filter(m -> parametersCompatible(m.getParameters(), row))\n    .filter(m -> PTransform.class.isAssignableFrom(m.getReturnType()))\n    .count();\nif (matches > 1) throw new IllegalStateException(\"Ambiguous builder method for \" + name);\n","typeGuard":null,"tryCatchPattern":"try {\n  return getTransform(payload);\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"Expected to find exactly one matching method\")) {\n    throw new InvalidExpansionRequest(\"Ambiguous overload for builder method; refine payload types\", e);\n  }\n  throw e;\n}","preventionTips":["Do not overload builder methods that are exposed to cross-language expansion.","Differentiate overloads by distinct method names instead of parameter types.","Tighten payload field types (ARRAY vs scalar) so only one overload is compatible.","Add unit tests that resolve each exposed builder method via the provider."],"tags":["java","reflection","overload-ambiguity","beam-expansion-service"],"backgroundTag":"ambiguous-overload","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"}