apache/beam · error · java.lang.RuntimeException

Expected to find exactly one matching method in transform …

Error message

Expected to find exactly one matching method in transform  for BuilderMethod but found 

What it means

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.

Solutions

  1. Remove or rename the ambiguous overload in the transform so exactly one builder method matches the payload schema.
  2. Make the payload parameter schema more specific (correct array vs scalar types) so only one overload is compatible.
  3. Use an explicit @MultiLanguageBuilderMethod-named method that is unique for the requested operation.

Example fix

// before
public MyTransform withTags(List<String> tags) {...}
public MyTransform withTags(String[] tags) {...}
// after
public MyTransform withTags(List<String> tags) {...}  // single overload
Defensive patterns

Strategy: validation

Validate before calling

long matches = Stream.of(transformClass.getMethods())
    .filter(m -> methodMatchesName(m, name))
    .filter(m -> parametersCompatible(m.getParameters(), row))
    .filter(m -> PTransform.class.isAssignableFrom(m.getReturnType()))
    .count();
if (matches > 1) throw new IllegalStateException("Ambiguous builder method for " + name);

Try / catch

try {
  return getTransform(payload);
} catch (RuntimeException e) {
  if (e.getMessage() != null && e.getMessage().contains("Expected to find exactly one matching method")) {
    throw new InvalidExpansionRequest("Ambiguous overload for builder method; refine payload types", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Adding an overload like withTags(List<String>) alongside withTags(String[]) making the payload ambiguous; payload schema generic enough to match several overloads.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/8689fbbbddca2a73. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/expansion-service/src/main/java/org/apache/beam/sdk/expansion/service/JavaClassLookupTransformProvider.java:232

    Row builderMethodRow = decodeRow(builderMethod.getSchema(), builderMethod.getPayload());

    List<Method> matchingMethods =
        Arrays.stream(transform.getClass().getMethods())
            .filter(m -> isBuilderMethodForName(m, builderMethod.getName(), allowListClass))
            .filter(m -> parametersCompatible(m.getParameters(), builderMethodRow))
            .filter(m -> PTransform.class.isAssignableFrom(m.getReturnType()))
            .collect(Collectors.toList());

    if (matchingMethods.size() == 0) {
      throw new RuntimeException(
          "Could not find a matching method in transform "
              + transform
              + " for BuilderMethod"
              + builderMethod
              + ". When using field names, make sure they are available in the compiled"
              + " Java class.");
    } else if (matchingMethods.size() > 1) {
      throw new RuntimeException(
          "Expected to find exactly one matching method in transform "
              + transform
              + " for BuilderMethod"
              + builderMethod
              + " but found "
              + matchingMethods.size());
    }
    return matchingMethods.get(0);
  }

  private static boolean isPrimitiveOrWrapperOrString(java.lang.Class<?> type) {
    return ClassUtils.isPrimitiveOrWrapper(type) || type == String.class;
  }

  private Schema getParameterSchema(Class<?> parameterClass) {
    Schema parameterSchema;
    try {
      parameterSchema = SCHEMA_REGISTRY.getSchema(parameterClass);

View on GitHub (pinned to 12126d8942)