apache/beam · error · UnsupportedOperationException

ProcessContext unsupported in

Error message

ProcessContext unsupported in ${context}

What it means

DoFnInvoker.BaseArgumentProvider provides a default ArgumentProvider whose processContext() always throws UnsupportedOperationException. The Beam pipeline machinery substitutes a real, context-aware ArgumentProvider when a method actually needs a ProcessContext; hitting this default means the surrounding context does not support ProcessContext access.

Solutions

  1. Check where the DoFn method is being invoked: access ProcessContext only from @ProcessElement methods
  2. In tests, provide a stub ArgumentProvider that overrides processContext() instead of using BaseArgumentProvider defaults
  3. Use DoFnInvokers.invokerForFn() / the generated invoker so Beam installs the correct ArgumentProvider
  4. If you own the runner/integration code, pass an ArgumentProvider that implements processContext()

Example fix

// before (test stub)
new DoFnInvoker.BaseArgumentProvider<String, String>() {};
// after
new DoFnInvoker.BaseArgumentProvider<String, String>() {
  @Override
  public DoFn<String, String>.ProcessContext processContext(DoFn<String, String> doFn) {
    return fakeProcessContext; // supplied by the test harness
  }
};
Defensive patterns

Strategy: type-guard

Validate before calling

// Only access ProcessContext from @ProcessElement methods:
boolean inProcessElement = method.isAnnotationPresent(org.apache.beam.sdk.transforms.DoFn.ProcessElement.class);
if (!inProcessElement) {
  throw new IllegalStateException("ProcessContext is only available in @ProcessElement");
}

Type guard

static boolean hasProcessContext(DoFnInvoker.ArgumentProvider<?, ?> p) {
  try { p.processContext(null); return true; }
  catch (UnsupportedOperationException e) { return false; }
}

Try / catch

try {
  doFnInvoker.invokeProcessElement(args);
} catch (UnsupportedOperationException e) {
  throw new IllegalStateException(
      "ProcessContext unavailable here (" + e.getMessage() + "); move access into @ProcessElement", e);
}

Prevention

When it happens

Trigger: Calling doFn.processContext(...) (or invoking a method that requests a ProcessContext parameter) with the default BaseArgumentProvider that was not replaced — e.g. invoking a DoFn method in a context that is not a proper element-processing step, or tests calling methods directly with a plain invoker.

Common situations: Unit tests that construct a DoFnInvoker with the default BaseArgumentProvider and then call methods requiring a ProcessContext; calling a @ProcessElement-style method from @StartBundle/@FinishBundle where only bundle context is available; runner-side bugs invoking a DoFn with the wrong ArgumentProvider.

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/65c7671e49a96306. Report an issue: GitHub.

Appendix: source

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

     */
    TimerMap timerFamily(String tagId);

    /**
     * Returns the timer id for the current timer of a {@link
     * org.apache.beam.sdk.transforms.DoFn.TimerFamily}.
     */
    String timerId(DoFn<InputT, OutputT> doFn);
  }

  /**
   * This {@link ArgumentProvider} throws {@link UnsupportedOperationException} for all parameters.
   */
  @Internal
  abstract class BaseArgumentProvider<InputT, OutputT>
      implements ArgumentProvider<InputT, OutputT> {
    @Override
    public DoFn<InputT, OutputT>.ProcessContext processContext(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(
          String.format("ProcessContext unsupported in %s", getErrorContext()));
    }

    @Override
    public InputT element(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(
          String.format("Element unsupported in %s", getErrorContext()));
    }

    @Override
    public @Nullable Object key() {
      throw new UnsupportedOperationException(
          "Cannot access key as parameter outside of @OnTimer method.");
    }

    @Override
    public @Nullable Object sideInput(String tagId) {
      throw new UnsupportedOperationException(

View on GitHub (pinned to 12126d8942)