apache/beam · error · UnsupportedOperationException

Cannot access timerId as parameter outside of @OnTimer metho

Error message

Cannot access timerId as parameter outside of @OnTimer method.

What it means

FnApiDoFnRunner.timerId() backs the timer-id parameter exposed to @OnTimer methods (TimerId param / context.timerId()). The runner only records the active timer id while dispatching a fired timer; outside that window there is no timer id to return, so it throws UnsupportedOperationException unconditionally. It is a misuse guard, not an internal failure.

Source

Thrown at sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java:2072

    @Override
    public @Nullable String currentRecordId(DoFn<InputT, OutputT> doFn) {
      return currentRecordId();
    }

    @Override
    public @Nullable Long currentRecordOffset(DoFn<InputT, OutputT> doFn) {
      return currentRecordOffset();
    }

    @Override
    public Instant fireTimestamp(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(
          "Cannot access fire timestamp outside of @OnTimer method.");
    }

    @Override
    public String timerId(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(
          "Cannot access timerId as parameter outside of @OnTimer method.");
    }

    @Override
    public TimeDomain timeDomain(DoFn<InputT, OutputT> doFn) {
      throw new UnsupportedOperationException(
          "Cannot access time domain outside of @ProcessTimer method.");
    }

    @Override
    public OutputReceiver<OutputT> outputReceiver(DoFn<InputT, OutputT> doFn) {
      return this;
    }

    @Override
    // OutputT == RestrictionT
    public void output(OutputT output) {
      OutputReceiver.super.output(output);

View on GitHub (pinned to 12126d8942)

Solutions

  1. Move timerId() access (or the TimerId parameter) into the @OnTimer-annotated method only.
  2. Pass the timer id explicitly as a plain argument when shared helper code needs it from a timer callback.
  3. If the timer name is needed statically for setup, hardcode/derive the id constant used in the Timer.withTimeDomain(...)/Timer.of call instead of reading it from the context.
  4. Check that the method containing the access carries @OnTimer and the correct timer family/id.

Example fix

// before
@ProcessElement
public void processElement(ProcessContext c) {
  String id = c.timerId(); // throws
}
// after
@OnTimer("cleanup")
public void onTimer(OnTimerContext c) {
  String id = c.timerId(); // valid only here
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the accessor is only called from a method annotated @OnTimer
Method m = /* currently executing method */;
if (m == null || !m.isAnnotationPresent(OnTimer.class)) {
  throw new IllegalStateException("timerId is only available inside @OnTimer");
}

Type guard

static boolean canReadTimerId(DoFn.ProcessContext c) {
  return c instanceof DoFn.OnTimerContext;
}

Try / catch

try {
  String id = ((DoFn.OnTimerContext) c).timerId();
} catch (UnsupportedOperationException e) {
  // outside @OnTimer: use the static timer id string instead
  String id = "cleanup";
}

Prevention

When it happens

Trigger: Calling context.timerId() (or declaring a TimerId/String timer-id parameter) from @ProcessElement, @StartBundle, @FinishBundle, or a watermark-expiration path rather than from a @OnTimer-annotated method. Any DoFn signature resolution that binds timerId for a non-timer invocation.

Common situations: Refactoring @OnTimer logic into shared helpers invoked from both element and timer paths; declaring a TimerId parameter on the wrong method; copying examples where the annotation was dropped during editing, so the harness treats the method as element processing.

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