apache/beam · error · IllegalArgumentException

Found multiple methods annotated with @%s. [%s] and [%s]

Error message

Found multiple methods annotated with @%s. [%s] and [%s]

What it means

After collecting all @ApplyMethod-annotated methods of a ScalarFn, getApplyMethod allows multiple matches only if they are overrides of each other (same name and parameter types, inherited from parent classes). If two distinct annotated methods with different names or signatures are found, the invocation target is ambiguous and an IllegalArgumentException naming both methods is thrown.

Source

Thrown at sdks/java/extensions/sql/src/main/java/org/apache/beam/sdk/extensions/sql/impl/ScalarFnReflector.java:56

    Collection<Method> matches =
        ReflectHelpers.declaredMethodsWithAnnotation(
            ScalarFn.ApplyMethod.class, clazz, ScalarFn.class);

    if (matches.isEmpty()) {
      throw new IllegalArgumentException(
          String.format(
              "No method annotated with @%s found in class %s.",
              ScalarFn.ApplyMethod.class.getSimpleName(), clazz.getName()));
    }

    // If we have at least one match, then either it should be the only match
    // or it should be an extension of the other matches (which came from parent
    // classes).
    Method first = matches.iterator().next();
    for (Method other : matches) {
      if (!first.getName().equals(other.getName())
          || !Arrays.equals(first.getParameterTypes(), other.getParameterTypes())) {
        throw new IllegalArgumentException(
            String.format(
                "Found multiple methods annotated with @%s. [%s] and [%s]",
                ScalarFn.ApplyMethod.class.getSimpleName(),
                ReflectHelpers.formatMethod(first),
                ReflectHelpers.formatMethod(other)));
      }
    }

    // Method must be public.
    if ((first.getModifiers() & Modifier.PUBLIC) == 0) {
      throw new IllegalArgumentException(
          String.format("Method %s is not public.", ReflectHelpers.formatMethod(first)));
    }

    return first;
  }
}

View on GitHub (pinned to 12126d8942)

Solutions

  1. Keep exactly one logical @ApplyMethod method per ScalarFn; annotate only the one you want invoked.
  2. For overloads, remove @ApplyMethod from all but the target overload or split into separate ScalarFn classes.
  3. If a parent and child override the same signature, that is allowed — make the signatures identical (same parameter types) so it is recognized as an override.
  4. Search the class hierarchy (including superclasses) for stray @ApplyMethod annotations and remove them.

Example fix

// before
@ApplyMethod public String apply(String s) { ... }
@ApplyMethod public String apply(String s, Integer n) { ... } // ambiguous
// after
@ApplyMethod public String apply(String s) { ... }
public String apply(String s, Integer n) { ... } // unannotated helper
Defensive patterns

Strategy: validation

Validate before calling

static void checkSingleApplyMethod(ScalarFn fn) {
  java.util.Set<String> sigs = new java.util.HashSet<>();
  for (java.lang.reflect.Method m : fn.getClass().getMethods()) {
    if (m.isAnnotationPresent(ScalarFn.ApplyMethod.class)
        && !sigs.add(m.getName() + java.util.Arrays.toString(m.getParameterTypes())))
      throw new IllegalStateException("multiple distinct @ApplyMethod methods in " + fn.getClass());
  }
}

Try / catch

try {
  ScalarFnReflector.getApplyMethod(scalarFn);
} catch (IllegalArgumentException e) {
  if (e.getMessage().startsWith("Found multiple methods")) {
    throw new IllegalStateException("Keep only one @ApplyMethod overload per ScalarFn", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: A ScalarFn class (or its superclass chain) declares two @ApplyMethod-annotated methods with different signatures or names — e.g. apply(String) and apply(String, Integer) both annotated, or two differently named methods both marked @ApplyMethod.

Common situations: Overloading the apply method and annotating every overload; adding a second apply for a new type during refactoring; a superclass and subclass each annotating genuinely different methods.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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