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
- Move timerId() access (or the TimerId parameter) into the @OnTimer-annotated method only.
- Pass the timer id explicitly as a plain argument when shared helper code needs it from a timer callback.
- 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.
- 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
- Declare TimerId parameters only on @OnTimer methods
- Never share a single context helper across element and timer paths
- Pass the timer id explicitly to shared helpers from the @OnTimer method
- Review DoFn annotations after refactors; the harness binds params by annotation
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
- TimerFamily unsupported in ${context}
- FireTimestamp unsupported in %s
- CausedByDrain unsupported in %s
- Cannot access fire timestamp outside of @OnTimer method.
- Cannot access timerId as parameter outside of @OnTimer metho
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/58c80e3845021cf0.
Report an issue: GitHub.