{"record":{"id":"84bcee1d5bcf2b9d","repo":"apache/beam","slug":"attempting-to-emit-an-element-outside-of-a-processelement","errorCode":null,"errorMessage":"Attempting to emit an element outside of a @ProcessElement context.","messagePattern":"Attempting to emit an element outside of a @ProcessElement context\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java","lineNumber":1879,"sourceCode":"  private class NonWindowObservingProcessBundleContext\n      extends NonWindowObservingProcessBundleContextBase {\n\n    @Override\n    public OutputBuilder<OutputT> builder(OutputT value) {\n      return WindowedValues.builder(currentElement)\n          .withValue(value)\n          .setReceiver(\n              windowedValue -> {\n                checkTimestamp(windowedValue.getTimestamp());\n                outputTo(mainOutputConsumer, windowedValue);\n              });\n    }\n\n    @Override\n    public void output(OutputT output) {\n      // Don't need to check timestamp since we can always output using the input timestamp.\n      if (currentElement == null) {\n        throw new IllegalStateException(\n            \"Attempting to emit an element outside of a @ProcessElement context.\");\n      }\n      outputTo(mainOutputConsumer, currentElement.withValue(output));\n    }\n\n    @Override\n    public <T> void output(TupleTag<T> tag, T output) {\n      FnDataReceiver<WindowedValue<T>> consumer =\n          (FnDataReceiver) localNameToConsumer.get(tag.getId());\n      if (consumer == null) {\n        throw new IllegalArgumentException(String.format(\"Unknown output tag %s\", tag));\n      }\n      // Don't need to check timestamp since we can always output using the input timestamp.\n      outputTo(consumer, currentElement.withValue(output));\n    }\n\n    @Override\n    public void outputWithTimestamp(OutputT output, Instant timestamp) {","sourceCodeStart":1861,"sourceCodeEnd":1897,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/harness/src/main/java/org/apache/beam/fn/harness/FnApiDoFnRunner.java#L1861-L1897","documentation":"Thrown as IllegalStateException when SingleOutputReceiver.output is invoked while currentElement is null, i.e. emission is attempted outside @ProcessElement (or @StartBundle/@FinishBundle contexts that don't have an element). Outputting the main output requires an active current element whose metadata (timestamp, window, pane) can be reused.","triggerScenarios":"Calling c.output(value) from a timer callback (onTimer), from @StartBundle/@FinishBundle, or from an async thread after @ProcessElement returned; storing the ProcessContext in a field and calling output later.","commonSituations":"Emitting from onTimerContext using the element-context API instead of Timer output; leaking context into ExecutorService callbacks; FinishBundle code that reuses the ProcessContext captured during ProcessElement.","solutions":["Only call output() within @ProcessElement; from @OnTimer use the timer context or timers to emit side effects.","Buffer elements during @ProcessElement and emit them in the same call; use @FinishBundle with its own FinishBundleContext.output API instead of the element context.","Capture the value (not the context) if you must emit from async code, then emit synchronously before ProcessElement returns (or use runner-supported async output APIs).","Add an assertion/guard that currentElement != null in helper methods that call output."],"exampleFix":"// before\n@OnTimer(\"t\")\npublic void onTimer(OnTimerContext ctx) { ctx.output(result); } // wrong context usage pattern\n\n// after: emit during @ProcessElement or buffer and use bundle context\n@FinishBundle\npublic void finish(FinishBundleContext ctx) { ctx.output(MAIN_TAG, bufferedResult, Instant.now(), window); }","handlingStrategy":"validation","validationCode":"if (context == null || !inProcessElement) {\n  throw new IllegalStateException(\"output() called outside @ProcessElement\");\n}","typeGuard":"boolean canEmit(ProcessContext c) { return c != null && currentElement() != null; }","tryCatchPattern":"try {\n  c.output(value);\n} catch (IllegalStateException e) {\n  logger.error(\"Emission attempted outside @ProcessElement; buffer for FinishBundle instead\", e);\n}","preventionTips":["Never store ProcessContext in a field for later use","Emit from onTimer using timer context APIs, not element output","Do async work inside ProcessElement and emit before returning"],"tags":["beam","dofn","lifecycle","illegal-state"],"backgroundTag":"invalid-state-transition","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-15T02:17:10.978Z"}