{"record":{"id":"acbd551aa2d4e375","repo":"apache/beam","slug":"cannot-access-onwindowexpirationcontext-outside-of","errorCode":null,"errorMessage":"Cannot access OnWindowExpirationContext outside of @OnWindowExpiration methods.","messagePattern":"Cannot access OnWindowExpirationContext outside of @OnWindowExpiration methods\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java","lineNumber":2218,"sourceCode":"    public BundleFinalizer bundleFinalizer() {\n      return bundleFinalizer;\n    }\n\n    @Override\n    public Object restriction() {\n      return currentRestriction;\n    }\n\n    @Override\n    public DoFn<InputT, OutputT>.OnTimerContext onTimerContext(DoFn<InputT, OutputT> doFn) {\n      throw new UnsupportedOperationException(\n          \"Cannot access OnTimerContext outside of @OnTimer methods.\");\n    }\n\n    @Override\n    public DoFn<InputT, OutputT>.OnWindowExpirationContext onWindowExpirationContext(\n        DoFn<InputT, OutputT> doFn) {\n      throw new UnsupportedOperationException(\n          \"Cannot access OnWindowExpirationContext outside of @OnWindowExpiration methods.\");\n    }\n\n    @Override\n    public RestrictionTracker<?, ?> restrictionTracker() {\n      return currentTracker;\n    }\n\n    @Override\n    public PipelineOptions getPipelineOptions() {\n      return pipelineOptions;\n    }\n\n    @Override\n    public PipelineOptions pipelineOptions() {\n      return pipelineOptions;\n    }\n","sourceCodeStart":2200,"sourceCodeEnd":2236,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java#L2200-L2236","documentation":"This accessor supplies a DoFn<InputT, OutputT>.OnWindowExpirationContext, which is only valid while the harness executes a method annotated with @OnWindowExpiration. At all other times (element processing, timers, bundle lifecycle) there is no window-expiration context, so FnApiDoFnRunner throws UnsupportedOperationException. Note the message says 'methods' (plural) — the same guard covers every non-expiration lifecycle phase.","triggerScenarios":"Calling context.onWindowExpirationContext(doFn) from @ProcessElement, @OnTimer, @StartBundle/@FinishBundle, or anywhere other than a @OnWindowExpiration-annotated method; framework code resolving the context for the wrong lifecycle callback.","commonSituations":"Implementing @OnWindowExpiration on a runner/harness combination that does not yet support it and probing the context elsewhere; generic DoFn helper code that requests all context variants; version mismatches where window-expiration support was added to the DoFn API but the harness path throws outside the proper callback.","solutions":["Access onWindowExpirationContext only from a method annotated with @OnWindowExpiration.","Use ProcessContext (or the OnTimerContext inside @OnTimer) for all other lifecycle phases.","Confirm the Fn API harness in your Beam version supports @OnWindowExpiration; if not, use timers (@OnTimer with a large TTL) or GC-triggers instead of window expiration callbacks.","If you need expiration-like cleanup, encode it via timer APIs or window triggering rather than requesting the expiration context from element code."],"exampleFix":"// before\n@ProcessElement\npublic void processElement(ProcessContext c) {\n  var ec = c.onWindowExpirationContext(myDoFn); // throws\n}\n// after\n@OnWindowExpiration\npublic void onWindowExpiration(OnWindowExpirationContext c) {\n  // valid only here\n}","handlingStrategy":"type-guard","validationCode":"if (!(c instanceof DoFn.OnWindowExpirationContext)) {\n  throw new IllegalStateException(\"onWindowExpirationContext requested outside @OnWindowExpiration\");\n}","typeGuard":"static boolean isOnWindowExpirationContext(DoFn.ProcessContext c) {\n  return c instanceof DoFn.OnWindowExpirationContext;\n}","tryCatchPattern":"try {\n  DoFn.OnWindowExpirationContext ec = runner.onWindowExpirationContext(doFn);\n  // use ec\n} catch (UnsupportedOperationException e) {\n  // not in @OnWindowExpiration; use ProcessContext or timer-based cleanup\n}","preventionTips":["Request OnWindowExpirationContext only from @OnWindowExpiration methods","Verify your Beam Fn API harness version supports @OnWindowExpiration before adopting it","Prefer timers or window triggers for cleanup logic if support is uncertain","Keep expiration logic isolated so generic context helpers never touch it"],"tags":["java","apache-beam","windows","context","unsupported-operation"],"backgroundTag":"unsupported-operation","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}