apache/beam · error · UnsupportedOperationException
OnTimerContext unsupported in
Error message
OnTimerContext unsupported in %s
What it means
The placeholder DoFnInvoker implementation throws UnsupportedOperationException when OnTimerContext is requested. OnTimerContext is only valid while dispatching an @OnTimer callback, and the stub invoker never provides one. getErrorContext() embeds the DoFn and call-site information in the message.
Solutions
- Build the invoker with DoFnInvokers.newInvoker/tryInvokeFor so the accessor is implemented
- Request OnTimerContext only from the timer dispatch path
- If writing a runner, override onTimerContext in your invoker subclass to supply the runner's timer context
Example fix
// before
new DoFnInvoker.BaseDoFnInvoker<T, O>(){}.onTimerContext(fn); // throws
// after
DoFnInvokers.tryInvokeFor(fn).onTimerContext(fn); Defensive patterns
Strategy: validation
Validate before calling
if (invoker.getClass().getSimpleName().contains("Unsupported")) {
throw new IllegalStateException("Stub invoker cannot provide OnTimerContext");
} Type guard
boolean supportsTimerContext(DoFnInvoker<?, ?> i) {
return i.getClass() != DoFnInvoker.BaseDoFnInvoker.class;
} Try / catch
try {
timerCtx = invoker.onTimerContext(doFn);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("Runner does not supply OnTimerContext", e);
} Prevention
- Only dispatch timer callbacks through the invoker's invokeOnTimer path
- Verify runner timer support before enabling @OnTimer DoFns
- Use generated invokers, never the raw base class
When it happens
Trigger: Invoking onTimerContext(...) (or onWindowExpirationContext(...) per the stub's chain of accessors) on an invoker instance that did not override that accessor — i.e. any invoker not built through DoFnInvokers' generated/reflective path.
Common situations: Custom runner code driving timers without a runner-provided invoker; unit tests instantiating the abstract base directly; accessing a timer context from a method that is not @OnTimer/@OnWindowExpiration.
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
- Cannot access fire timestamp outside of @OnTimer method.
- Cannot access OnTimerContext outside of @OnTimer methods.
- Cannot access time domain outside of @ProcessTimer method.
- Cannot access timerId as parameter outside of @OnTimer…
- CausedByDrain unsupported in
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/99a415e81b45e5b4.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/transforms/reflect/DoFnInvoker.java:452
}
@Override
public DoFn<InputT, OutputT>.FinishBundleContext finishBundleContext(
DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("FinishBundleContext unsupported in %s", getErrorContext()));
}
@Override
public DoFn<InputT, OutputT>.OnTimerContext onTimerContext(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("OnTimerContext unsupported in %s", getErrorContext()));
}
@Override
public DoFn<InputT, OutputT>.OnWindowExpirationContext onWindowExpirationContext(
DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
String.format("OnWindowExpirationContext unsupported in %s", getErrorContext()));
}
@Override
public State state(String stateId, boolean alwaysFetched) {
throw new UnsupportedOperationException(
String.format("State unsupported in %s", getErrorContext()));
}
@Override
public Timer timer(String timerId) {
throw new UnsupportedOperationException(
String.format("Timer unsupported in %s", getErrorContext()));
}
@Override
public RestrictionTracker<?, ?> restrictionTracker() {
throw new UnsupportedOperationException(View on GitHub (pinned to 12126d8942)