apache/beam · error · UnsupportedOperationException
Cannot access StartBundleContext outside of @StartBundle met
Error message
Cannot access StartBundleContext outside of @StartBundle method.
What it means
The invoker context used outside of @StartBundle methods throws UnsupportedOperationException when startBundleContext(doFn) is requested, because the StartBundleContext (which can emit output with bundle lifecycle semantics) only exists while running a @StartBundle method. Any other DoFn lifecycle method receives a context whose startBundleContext() is intentionally unimplemented.
Source
Thrown at sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java:2016
}
}
/** Base implementation that does not override methods which need to be window aware. */
private abstract class ProcessBundleContextBase extends DoFn<InputT, OutputT>.ProcessContext
implements DoFnInvoker.ArgumentProvider<InputT, OutputT>, OutputReceiver<OutputT> {
private ProcessBundleContextBase() {
doFn.super();
}
@Override
public PaneInfo paneInfo(DoFn<InputT, OutputT> doFn) {
return pane();
}
@Override
public DoFn<InputT, OutputT>.StartBundleContext startBundleContext(DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
"Cannot access StartBundleContext outside of @StartBundle method.");
}
@Override
public DoFn<InputT, OutputT>.FinishBundleContext finishBundleContext(
DoFn<InputT, OutputT> doFn) {
throw new UnsupportedOperationException(
"Cannot access FinishBundleContext outside of @FinishBundle method.");
}
@Override
public DoFn<InputT, OutputT>.ProcessContext processContext(DoFn<InputT, OutputT> doFn) {
return this;
}
@Override
public InputT element(DoFn<InputT, OutputT> doFn) {
return element();View on GitHub (pinned to 12126d8942)
Solutions
- Only access startBundleContext inside a method annotated with @StartBundle; refactor code that needs it into that method.
- If writing a custom invoker/advice, branch on the current lifecycle phase before calling startBundleContext.
- For emitting elements from @ProcessElement, use processContext or the normal output methods instead.
Example fix
// before
@ProcessElement
public void processElement(StartBundleContext ctx, ProcessContext c) {
ctx.output(mainTag, element); // wrong context, throws when accessed
}
// after
@StartBundle
public void startBundle(StartBundleContext ctx) {
ctx.output(mainTag, bootstrapValue);
}
@ProcessElement
public void processElement(ProcessContext c) {
c.output(element);
} Defensive patterns
Strategy: validation
Validate before calling
// Only use StartBundleContext inside @StartBundle methods; validate at registration time:
for (Method m : dofn.getClass().getDeclaredMethods()) {
if (m.getParameterCount() > 0
&& DoFn.StartBundleContext.class.isAssignableFrom(m.getParameterTypes()[0])
&& !m.isAnnotationPresent(StartBundle.class)) {
throw new IllegalStateException(m + " takes StartBundleContext but is not @StartBundle");
}
} Type guard
boolean isStartBundleMethod(Method m) {
return m.isAnnotationPresent(DoFn.StartBundle.class);
} Try / catch
try {
ctx.startBundleContext(doFn).output(tag, v);
} catch (UnsupportedOperationException e) {
throw new IllegalStateException("startBundleContext is only valid inside @StartBundle", e);
} Prevention
- Request StartBundleContext only as a parameter of a @StartBundle-annotated method.
- In custom DoFnInvoker advice, check the lifecycle phase before invoking context accessors.
- Emit per-element output with ProcessContext in @ProcessElement instead.
When it happens
Trigger: Calling invoker-context.startBundleContext(doFn) (directly or via DoFn API reflection) from @ProcessElement, @FinishBundle, @OnTimer, or @GetInitialRestriction-style methods.
Common situations: Custom DoFnInvoker.Advice implementations that unconditionally call startBundleContext(); generic framework code passing the context around and invoking all lifecycle accessors; unit-test harnesses driving a ProcessContext and calling startBundleContext.
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 FinishBundleContext outside of @FinishBundle m
- Cannot access window in non-window observing context.
- Cannot access sideInput in non-window observing context.
- Cannot access state in non-window observing context.
- Cannot access timer in non-window observing context.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/3e9db903a9bf8fad.
Report an issue: GitHub.