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

  1. Refactor the DoFn so core logic is in a plain method testable without the unsupported parameter
  2. Use TestPipeline (mini-runner) instead of DoFnTester for stateful/SDF/timer-based DoFns
  3. 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

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


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)