apache/beam · error · UnsupportedOperationException

TimerFamily unsupported in ${context}

Error message

TimerFamily unsupported in ${context}

What it means

This UnsupportedOperationException is thrown by DoFnInvoker.BaseArgumentProvider.timerFamily when a timer-family parameter is requested in a DoFn invocation context that cannot supply one. Timer families (DoFn.TimerMap / @TimerFamily) only exist while an @OnTimer method is firing, so every other context's ArgumentProvider leaves timerFamily un-overridden and inherits this throwing default. The context name is filled in by getErrorContext() so the developer can see where the illegal access happened.

Source

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

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

    @Override
    public @Nullable String currentRecordId(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(

View on GitHub (pinned to 12126d8942)

Solutions

  1. Only request a TimerMap inside @OnTimer methods; in @ProcessElement use DoFn.ProcessContext.timer(timerId) for individual timers instead.
  2. Verify the parameter's annotation/context matches the method it is declared on (e.g. @TimerFamily parameters belong on @OnTimer methods).
  3. Check the runner's support level for timer families (RunnerDAG capability) and upgrade the runner/SDK if TimerFamily is not yet supported.
  4. If implementing a custom ArgumentProvider, override timerFamily(String) to return the actual TimerMap for the firing context.

Example fix

// before
@ProcessElement
public void processElement(ProcessContext c) {
  c.timerFamily("cleanup").set(c.timestamp().plus(Duration.standardMinutes(5))); // throws
}

// after
@ProcessElement
public void processElement(ProcessContext c) {
  c.timer("cleanup").set(c.timestamp().plus(Duration.standardMinutes(5)));
}
Defensive patterns

Strategy: validation

Validate before calling

// TimerMap parameters are only valid on @OnTimer methods; check before building the pipeline.
DoFnSignature sig = DoFnSignatures.getSignature(doFn.getClass());
sig.timerFamilyDeclarations(); // ensure each declaration's receiver is an OnTimerContext method

Type guard

if (context instanceof DoFn.OnTimerContext) {
  // timer family access is only meaningful here
}

Try / catch

try {
  TimerMap timers = context.timerFamily("cleanup");
} catch (UnsupportedOperationException e) {
  // not a timer-firing context; schedule timers via ProcessContext.timer() instead
}

Prevention

When it happens

Trigger: Requesting a TimerMap (e.g. c.timerFamily("family") or an @TimerFamily annotated parameter) from a context other than a firing timer: @ProcessElement, @StartBundle, @FinishBundle, @OnWindowExpiration methods, or custom ArgumentProviders that do not override timerFamily(String).

Common situations: Trying to set/reset timers from @ProcessElement via timerFamily instead of the per-timer c.timer(...) API; declaring a TimerMap parameter on a non-@OnTimer method and letting the invoker bind it; SDK/runner mismatch where the runner's ArgumentProvider does not yet support TimerFamily (older runners or Flink/Spark versions predating timer families).

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