apache/beam · error · UnsupportedOperationException
Parameter not supported by DoFnTester
Error message
Parameter %s not supported by DoFnTester
What it means
DoFnTester simulates only a subset of DoFn parameter types. When preparing a context method (e.g. @ProcessElement) whose signature requires a parameter type it doesn't handle (anything beyond timer-id, timestamp, window, etc.), it throws this UnsupportedOperationException naming the parameter.
Solutions
- Refactor the DoFn so core logic is in a plain method testable without the unsupported parameter
- Use TestPipeline (mini-runner) instead of DoFnTester for stateful/SDF/timer-based DoFns
- Move state/timer interactions behind an interface and mock it in unit tests
Example fix
// before tester.processElement(...); // DoFn takes RestrictionTracker parameter // after TestPipeline p = TestPipeline.create(); p.apply(...).apply(ParDo.of(new MySdf()));
Defensive patterns
Strategy: validation
Validate before calling
// Inspect the ProcessElement method params before choosing DoFnTester
for (Method m : myDoFn.getClass().getDeclaredMethods()) {
if (m.isAnnotationPresent(DoFn.ProcessElement.class)) {
for (Class<?> p : m.getParameterTypes()) {
if (RestrictionTracker.class.isAssignableFrom(p)
|| WatermarkEstimator.class.isAssignableFrom(p)
|| Timer.class.isAssignableFrom(p)) {
throw new IllegalArgumentException("Use TestPipeline, not DoFnTester");
}
}
}
} Type guard
boolean doFnTesterSupported(DoFn<?, ?> fn) {
return java.util.Arrays.stream(fn.getClass().getDeclaredMethods())
.filter(m -> m.isAnnotationPresent(DoFn.ProcessElement.class)
|| m.isAnnotationPresent(DoFn.OnTimer.class))
.flatMap(m -> java.util.Arrays.stream(m.getParameterTypes()))
.noneMatch(p -> p.getSimpleName().equals("RestrictionTracker")
|| p.getSimpleName().equals("WatermarkEstimator"));
} Try / catch
try { tester.processElement(); }
catch (UnsupportedOperationException e) { /* switch to TestPipeline-based test */ } Prevention
- Refactor heavy logic out of the DoFn so unit tests don't need exotic parameters
- Use DoFnTester only for simple element-wise DoFns
- Any DoFn with timers, state, or restriction tracking should be tested via TestPipeline
When it happens
Trigger: Using DoFnTester on a DoFn whose ProcessElement/OnTimer method takes unsupported parameters such as RestrictionTracker, WatermarkEstimator, BundleFinalizer, or Timer/TimeDomain parameters.
Common situations: Unit-testing a splittable DoFn or a stateful/timer DoFn with DoFnTester; Beam version upgrades where a new parameter type was added before DoFnTester support.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Cannot access key as parameter outside of @OnTimer method.
- Cannot access timerId as parameter outside of @OnTimer…
- Not expected to access DoFn.FinishBundleContext from…
- Not expected to access DoFn.StartBundleContext from…
- Not expected to access Restriction from a regular DoFn in…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/3568dc886790a72c.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/DoFnTester.java:877
@Override
public @Nullable Void dispatch(
DoFnSignature.Parameter.TaggedOutputReceiverParameter p) {
return null;
}
@Override
public @Nullable Void dispatch(DoFnSignature.Parameter.PaneInfoParameter p) {
return null;
}
@Override
public Void dispatch(DoFnSignature.Parameter.TimerIdParameter p) {
return null;
}
@Override
protected Void dispatchDefault(DoFnSignature.Parameter p) {
throw new UnsupportedOperationException(
"Parameter " + p + " not supported by DoFnTester");
}
});
}
}
@SuppressWarnings("unchecked")
private void initializeState() throws Exception {
checkState(state == State.UNINITIALIZED, "Already initialized");
checkState(fn == null, "Uninitialized but fn != null");
if (cloningBehavior.equals(CloningBehavior.DO_NOT_CLONE)) {
fn = origFn;
} else {
fn =
(DoFn<InputT, OutputT>)
SerializableUtils.deserializeFromByteArray(
SerializableUtils.serializeToByteArray(origFn), origFn.toString());
}View on GitHub (pinned to 12126d8942)