{"record":{"id":"bc342b24683b6659","repo":"apache/beam","slug":"cannot-access-timerfamily-in-non-window-observing-context","errorCode":null,"errorMessage":"Cannot access timerFamily in non-window observing context.","messagePattern":"Cannot access timerFamily in non-window observing context\\.","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java","lineNumber":1996,"sourceCode":"      throw new UnsupportedOperationException(\n          \"Cannot access sideInput in non-window observing context.\");\n    }\n\n    @Override\n    public State state(String stateId, boolean alwaysFetched) {\n      throw new UnsupportedOperationException(\n          \"Cannot access state in non-window observing context.\");\n    }\n\n    @Override\n    public org.apache.beam.sdk.state.Timer timer(String timerId) {\n      throw new UnsupportedOperationException(\n          \"Cannot access timer in non-window observing context.\");\n    }\n\n    @Override\n    public TimerMap timerFamily(String timerFamilyId) {\n      throw new UnsupportedOperationException(\n          \"Cannot access timerFamily in non-window observing context.\");\n    }\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","sourceCodeStart":1978,"sourceCodeEnd":2014,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java#L1978-L2014","documentation":"NonWindowObservingProcessBundleContextBase.timerFamily(String) throws UnsupportedOperationException because timer families, like individual timers, are scoped to a window; without a bound window in a non-window-observing context the harness cannot resolve them.","triggerScenarios":"Calling c.timerFamily(timerFamilyId) (TimerMap creation) from a @ProcessElement method without a BoundedWindow parameter, or from @StartBundle/@FinishBundle.","commonSituations":"Migrating groups of timers to @TimerId/@TimerFamily declarations and calling timerFamily from non-window-observing code; setting dynamic timer families during bundle lifecycle methods.","solutions":["Add a BoundedWindow parameter to the @ProcessElement signature so the window-observing context (which implements timerFamily) is used.","Declare the timer family with @TimerId/@TimerFamily annotations and only access it inside @ProcessElement on a keyed PCollection.","Replace family-based dynamic timer ids with individual declared @TimerId timers if only a fixed set is needed."],"exampleFix":"// before\n@ProcessElement\npublic void processElement(ProcessContext c) {\n  c.timerFamily(\"family\").get(\"t1\").set(...); // throws\n}\n\n// after\n@ProcessElement\npublic void processElement(ProcessContext c, BoundedWindow window) {\n  c.timerFamily(\"family\").get(\"t1\").set(...);\n}","handlingStrategy":"validation","validationCode":"// Timer families require a window-observing context; verify before using timerFamily():\nboolean windowed = Arrays.stream(dofn.getClass().getDeclaredMethods())\n    .filter(m -> m.isAnnotationPresent(ProcessElement.class))\n    .anyMatch(m -> Arrays.asList(m.getParameterTypes()).contains(BoundedWindow.class));\nif (!windowed) throw new IllegalStateException(\"timerFamily needs BoundedWindow in @ProcessElement\");","typeGuard":"boolean hasTimerFamilySupport(DoFn<?> doFn) {\n  return Arrays.stream(doFn.getClass().getDeclaredFields())\n      .anyMatch(f -> f.isAnnotationPresent(TimerFamily.class))\n      && Arrays.stream(doFn.getClass().getDeclaredMethods())\n          .filter(m -> m.isAnnotationPresent(ProcessElement.class))\n          .anyMatch(m -> Arrays.asList(m.getParameterTypes()).contains(BoundedWindow.class));\n}","tryCatchPattern":"try {\n  c.timerFamily(\"family\").get(\"t1\").set(t);\n} catch (UnsupportedOperationException e) {\n  throw new IllegalStateException(\"timerFamily requires a window-observing @ProcessElement\", e);\n}","preventionTips":["Declare timer families via @TimerFamily/@TimerId annotations before use.","Keep all timer access inside @ProcessElement with a BoundedWindow parameter.","Use plain @TimerId timers when a fixed set suffices; reserve families for dynamic ids."],"tags":["java","beam","apache-beam","timers","dofn"],"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"}