{"record":{"id":"3e9db903a9bf8fad","repo":"apache/beam","slug":"cannot-access-startbundlecontext-outside-of-startbundle","errorCode":null,"errorMessage":"Cannot access StartBundleContext outside of @StartBundle method.","messagePattern":"Cannot access StartBundleContext outside of @StartBundle method\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java","lineNumber":2016,"sourceCode":"    }\n  }\n\n  /** Base implementation that does not override methods which need to be window aware. */\n  private abstract class ProcessBundleContextBase extends DoFn<InputT, OutputT>.ProcessContext\n      implements DoFnInvoker.ArgumentProvider<InputT, OutputT>, OutputReceiver<OutputT> {\n\n    private ProcessBundleContextBase() {\n      doFn.super();\n    }\n\n    @Override\n    public PaneInfo paneInfo(DoFn<InputT, OutputT> doFn) {\n      return pane();\n    }\n\n    @Override\n    public DoFn<InputT, OutputT>.StartBundleContext startBundleContext(DoFn<InputT, OutputT> doFn) {\n      throw new UnsupportedOperationException(\n          \"Cannot access StartBundleContext outside of @StartBundle method.\");\n    }\n\n    @Override\n    public DoFn<InputT, OutputT>.FinishBundleContext finishBundleContext(\n        DoFn<InputT, OutputT> doFn) {\n      throw new UnsupportedOperationException(\n          \"Cannot access FinishBundleContext outside of @FinishBundle method.\");\n    }\n\n    @Override\n    public DoFn<InputT, OutputT>.ProcessContext processContext(DoFn<InputT, OutputT> doFn) {\n      return this;\n    }\n\n    @Override\n    public InputT element(DoFn<InputT, OutputT> doFn) {\n      return element();","sourceCodeStart":1998,"sourceCodeEnd":2034,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java#L1998-L2034","documentation":"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.","triggerScenarios":"Calling invoker-context.startBundleContext(doFn) (directly or via DoFn API reflection) from @ProcessElement, @FinishBundle, @OnTimer, or @GetInitialRestriction-style methods.","commonSituations":"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.","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."],"exampleFix":"// before\n@ProcessElement\npublic void processElement(StartBundleContext ctx, ProcessContext c) {\n  ctx.output(mainTag, element); // wrong context, throws when accessed\n}\n\n// after\n@StartBundle\npublic void startBundle(StartBundleContext ctx) {\n  ctx.output(mainTag, bootstrapValue);\n}\n@ProcessElement\npublic void processElement(ProcessContext c) {\n  c.output(element);\n}","handlingStrategy":"validation","validationCode":"// Only use StartBundleContext inside @StartBundle methods; validate at registration time:\nfor (Method m : dofn.getClass().getDeclaredMethods()) {\n  if (m.getParameterCount() > 0\n      && DoFn.StartBundleContext.class.isAssignableFrom(m.getParameterTypes()[0])\n      && !m.isAnnotationPresent(StartBundle.class)) {\n    throw new IllegalStateException(m + \" takes StartBundleContext but is not @StartBundle\");\n  }\n}","typeGuard":"boolean isStartBundleMethod(Method m) {\n  return m.isAnnotationPresent(DoFn.StartBundle.class);\n}","tryCatchPattern":"try {\n  ctx.startBundleContext(doFn).output(tag, v);\n} catch (UnsupportedOperationException e) {\n  throw new IllegalStateException(\"startBundleContext is only valid inside @StartBundle\", e);\n}","preventionTips":["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."],"tags":["java","beam","apache-beam","dofn","lifecycle"],"backgroundTag":"unsupported-operation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}