apache/beam · error · UnsupportedOperationException
Cannot access fire timestamp outside of @OnTimer method.
Error message
Cannot access fire timestamp outside of @OnTimer method.
What it means
In Apache Beam's Fn API Java harness, DoFnSupportT.fireTimestamp() is the accessor backing the TimeParam/Instant 'fire timestamp' available only while executing a @OnTimer (or timer-firing) callback. FnApiDoFnRunner's ProcessContext implementation does not track a fire timestamp for ordinary element processing, so any request for the fire timestamp outside a timer callback throws UnsupportedOperationException. This guards against reading timer state that is meaningless during normal bundle/element processing.
Source
Thrown at sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java:2066
@Override
public Instant timestamp(DoFn<InputT, OutputT> doFn) {
return timestamp();
}
@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;View on GitHub (pinned to 12126d8942)
Solutions
- Move the fireTimestamp() call (or the Instant/timer-timestamp parameter) into a method annotated with @OnTimer only.
- If the timestamp is needed for elements, use the element's timestamp instead: c.timestamp() on the ProcessContext, which is valid inside @ProcessElement.
- If firing info must flow to non-timer code, capture fireTimestamp inside the @OnTimer method and pass it explicitly (e.g. as a method argument or state variable).
- Verify the method's annotations with DoFnSigatures/annotation checks so the harness binds timer parameters only for @OnTimer methods.
Example fix
// before
@ProcessElement
public void processElement(ProcessContext c) {
Instant ts = c.fireTimestamp(); // throws
...
}
// after
@ProcessElement
public void processElement(ProcessContext c) {
Instant ts = c.timestamp(); // element timestamp, always valid
...
}
@OnTimer("myTimer")
public void onTimer(OnTimerContext c) {
Instant fireTs = c.fireTimestamp(); // valid here
...
} Defensive patterns
Strategy: validation
Validate before calling
// Before reading a timer-only value, confirm you are in a timer callback:
boolean inOnTimer = getClass().getEnclosingMethod() != null
&& getClass().getEnclosingMethod().isAnnotationPresent(OnTimer.class);
if (!inOnTimer) {
Instant ts = processContext.timestamp(); // element timestamp instead of fireTimestamp()
} Type guard
static boolean canReadFireTimestamp(DoFn.ProcessContext c) {
return c instanceof DoFn.OnTimerContext;
} Try / catch
try {
Instant fireTs = ((DoFn.OnTimerContext) c).fireTimestamp();
} catch (UnsupportedOperationException e) {
// not in a @OnTimer callback; fall back to element timestamp
Instant ts = ((DoFn.ProcessContext) c).timestamp();
} Prevention
- Only read fireTimestamp/timerId/timeDomain inside @OnTimer methods
- Use c.timestamp() for element timestamps in @ProcessElement
- Keep timer-path and element-path code in separate methods so timer-only params never leak
- Add a unit test that invokes each DoFn lifecycle method through a real runner
When it happens
Trigger: Calling doFnProcessContext.fireTimestamp() (or injecting an Instant via @Timestamp-style timer param resolution, e.g. DoFnSignatures requesting TimeDomain/Instant params) from a @ProcessElement, @StartBundle, or @FinishBundle method instead of from inside a @OnTimer method. Also occurs when DoFn signature inspection wires fireTimestamp into a non-timer invocation path.
Common situations: A developer refactors timer-handling code and reuses a helper that reads fireTimestamp from the context in the element path; a DoFn declares a fire-timestamp parameter but the method is not annotated @OnTimer; copying timer logic into @ProcessElement while migrating from the classic runner to the portable Fn API harness.
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 timerId as parameter outside of @OnTimer metho
- Cannot access timerId as parameter outside of @OnTimer metho
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/87e705e8b2227a0b.
Report an issue: GitHub.