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

The timerId context parameter is only available inside @OnTimer callbacks. DoFnTester's ProcessContext throws UnsupportedOperationException when a @ProcessElement method requests timerId, since no timer is firing during element processing.

Source

Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/DoFnTester.java:321

            @Override
            public InputT element(DoFn<InputT, OutputT> doFn) {
              return processContext.element();
            }

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

            @Override
            public Instant timestamp(DoFn<InputT, OutputT> doFn) {
              return processContext.timestamp();
            }

            @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(
                  "Not expected to access TimeDomain from @ProcessElement");
            }

            @Override
            public OutputReceiver<OutputT> outputReceiver(DoFn<InputT, OutputT> doFn) {
              return DoFnOutputReceivers.windowedReceiver(processContext, builderSupplier, null);
            }

            @Override
            public MultiOutputReceiver taggedOutputReceiver(DoFn<InputT, OutputT> doFn) {
              return DoFnOutputReceivers.windowedMultiReceiver(
                  processContext, builderSupplier, null);

View on GitHub (pinned to 12126d8942)

Solutions

  1. Move the timerId parameter into the @OnTimer method only
  2. Pass the timer id as a constant/field (it's a compile-time known id) rather than a context parameter in processElement
  3. Refactor shared logic to not depend on timer identity outside timer callbacks

Example fix

// before
@ProcessElement public void process(ProcessContext c, @TimerId String id) {...}
// after
private static final String TIMER_ID = "myTimer";
@OnTimer(TIMER_ID) public void onTimer(@TimerId String id) {...}
Defensive patterns

Strategy: type-guard

Type guard

// TimerId only injectable in @OnTimer callbacks
boolean inOnTimer = method.isAnnotationPresent(OnTimer.class);

Try / catch

try {
  tester.processElement();
} catch (UnsupportedOperationException e) {
  // @TimerId parameter used in @ProcessElement
}

Prevention

When it happens

Trigger: Declaring a String timerId parameter (annotated as TimerId) in a @ProcessElement method run through DoFnTester.

Common situations: Copy-pasting @OnTimer signatures into @ProcessElement; DoFns sharing a helper that takes timerId and is also called from processElement.

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