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
- Remove the duplicate parameter so the method declares at most one of each type
- If two trackers are genuinely needed, restructure the DoFn — Beam's signature model allows only one per method
- 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
- Review splittable-DoFn method signatures for duplicated special parameters
- Keep one parameter of each context type per lifecycle method
- Run DoFn validation early (pipeline construction) to catch signature errors before runtime
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
- Missing required value for group [<group>]. At least one of
- --maxCacheMemoryUsagePercent must be between 0 and 100.
- GroupByEncryptedKey requires its input to use KvCoder
- the GroupByKey requires its output coder to be %s but found
- Expected size >= 0 but received ${size}.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/ca56ebedd3484b97.
Report an issue: GitHub.