apache/beam · error · IllegalStateException

Expected to have found at most one parameter of type %s but

Error message

Expected to have found at most one parameter of type %s but found %s.

What it means

DoFnSignatures.findParameter collects all parameters of a given type from a DoFn method signature and expects at most one. Finding more than one means the DoFn method declares duplicate context parameters (e.g. two RestrictionTrackerParameters or two WatermarkEstimatorParameters) — by default unsupported and possibly ambiguous — so an IllegalStateException is thrown.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/DoFnSignatures.java:443

    /** Indicates whether the specified {@link Parameter} is known in this context. */
    public boolean hasParameter(Class<? extends Parameter> type) {
      return extraParameters.stream().anyMatch(Predicates.instanceOf(type)::apply);
    }

    /**
     * Returns the specified {@link Parameter} if it is known in this context. Throws {@link
     * IllegalStateException} if there is more than one instance of the parameter.
     */
    public <T extends Parameter> Optional<T> findParameter(Class<T> type) {
      List<T> parameters = findParameters(type);
      switch (parameters.size()) {
        case 0:
          return Optional.empty();
        case 1:
          return Optional.of(parameters.get(0));
        default:
          throw new IllegalStateException(
              String.format(
                  "Expected to have found at most one parameter of type %s but found %s.",
                  type, parameters));
      }
    }

    public <T extends Parameter> List<T> findParameters(Class<T> type) {
      return (List<T>)
          extraParameters.stream().filter(Predicates.instanceOf(type)).collect(Collectors.toList());
    }

    /** State parameters declared in this context, keyed by {@link StateId}. */
    public Map<String, StateParameter> getStateParameters() {
      return Collections.unmodifiableMap(stateParameters);
    }

    /** Timer parameters declared in this context, keyed by {@link TimerId}. */
    public Map<String, TimerParameter> getTimerParameters() {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Remove the duplicate parameter so the method declares at most one of each type
  2. If two trackers are genuinely needed, restructure the DoFn — Beam's signature model allows only one per method
  3. Check the full validation error context in the IllegalStateException trace to find the offending method

Example fix

// before
@ProcessElement
public void process(ProcessContext c, RestrictionTracker<R, Long> t1, RestrictionTracker<R, Long> t2) { ... }
// after
@ProcessElement
public void process(ProcessContext c, RestrictionTracker<R, Long> tracker) { ... }
Defensive patterns

Strategy: validation

Validate before calling

long trackers = Arrays.stream(method.getParameterTypes())
    .filter(t -> RestrictionTracker.class.isAssignableFrom(t)).count();
if (trackers > 1) throw new IllegalArgumentException("At most one RestrictionTracker parameter allowed");

Type guard

boolean hasUniqueSpecialParams(Method m) {
  Set<Class<?>> seen = new HashSet<>();
  for (Class<?> t : m.getParameterTypes()) {
    if (!seen.add(t)) return false;
  }
  return true;
}

Try / catch

try {
  DoFnSignature sig = DoFnSignatures.getSignature(fn.getClass());
} catch (IllegalStateException e) {
  if (e.getMessage().contains("at most one parameter")) {
    throw new IllegalArgumentException("Fix duplicate DoFn method parameters", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Declaring a DoFn lifecycle method (e.g. @ProcessElement) with two parameters of the same special type, such as two RestrictionTracker parameters or two OnTimerContext parameters; this is flagged while building the DoFnSignature (findParameter is called by trackerT and watermarkEstimatorT signature checks).

Common situations: Copy-paste mistakes in a splittable DoFn method signature; refactoring that added a second tracker/estimator parameter; writing generic wrapper DoFns that accidentally duplicate parameter kinds.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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