apache/beam · error · UnsupportedOperationException

SideInput unsupported in ${context}

Error message

SideInput unsupported in ${context}

What it means

This UnsupportedOperationException is thrown by DoFnInvoker.BaseArgumentProvider.sideInput when a DoFn lifecycle method tries to bind a side input parameter in a context that does not support it. Beam's reflection-based invoker uses context-specific ArgumentProvider subclasses (StartBundle, ProcessElement, OnTimer, FinishBundle) that override only the accessors valid for that context; any accessor left un-overridden falls through to BaseArgumentProvider, which always throws. Side inputs are only resolvable during @ProcessElement processing, so other contexts deliberately reject them.

Source

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

      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(
          String.format("SideInput unsupported in %s", getErrorContext()));
    }

    @Override
    public TimerMap timerFamily(String tagId) {
      throw new UnsupportedOperationException(
          String.format("TimerFamily unsupported in %s", getErrorContext()));
    }

    @Override
    public @Nullable Object schemaElement(int index) {
      throw new UnsupportedOperationException(
          String.format("Schema element unsupported in %s", getErrorContext()));
    }

    @Override
    public Instant timestamp(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(

View on GitHub (pinned to 12126d8942)

Solutions

  1. Move the c.sideInput("tag") call (or the @SideInput annotated parameter) into the @ProcessElement method, where side inputs are supported.
  2. If the value is needed in @StartBundle/@FinishBundle, pass it as a plain field computed in @ProcessElement, or read it from a @Setup-time source that does not depend on side inputs.
  3. For @OnTimer, access only supported parameters (key, timer, fire timestamp); side inputs are not provided at timer firing time.
  4. If writing a custom ArgumentProvider (test harness / runner), override sideInput(String) to return the actual value instead of inheriting the BaseArgumentProvider default.

Example fix

// before
@StartBundle
public void startBundle(StartBundleContext c) {
  double threshold = (Double) c.sideInput("threshold"); // throws
}

// after
@ProcessElement
public void processElement(ProcessContext c) {
  double threshold = (Double) c.sideInput("threshold");
  process(c, threshold);
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate at pipeline construction time that side inputs are only used in @ProcessElement.
DoFnSignature sig = DoFnSignatures.getSignature(doFn.getClass());
if (!sig.processElement().sideInputs().isEmpty() && !sig.processElement().isPresent()) {
  throw new IllegalArgumentException("sideInput may only be used in @ProcessElement");
}

Type guard

// Narrow to the context that supports side inputs before calling.
if (context instanceof DoFn.ProcessContext) {
  Object v = ((DoFn.ProcessContext) context).sideInput("tag");
}

Try / catch

try {
  Object v = context.sideInput("tag");
} catch (UnsupportedOperationException e) {
  // sideInput not available in this lifecycle phase; use fallback value
  Object v = defaultValue;
}

Prevention

When it happens

Trigger: Declaring a DoFn sideInput parameter (e.g. c.sideInput("tag")) or a @SideInput-annotated argument in a method whose invocation context's ArgumentProvider does not override sideInput, such as @StartBundle, @FinishBundle, @OnTimer, or @OnWindowExpiration methods. This happens inside DoFnInvoker.invokeProcessMethod when it resolves the method's parameters against the context's ArgumentProvider.

Common situations: Refactoring a parameter lookup from a @ProcessElement method into a @StartBundle/@FinishBundle setup method (e.g. pre-loading a side input once per bundle); using side inputs inside @OnTimer callbacks expecting them to be available; custom runner or test ArgumentProvider subclasses that extend BaseArgumentProvider without overriding sideInput.

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