{"record":{"id":"4e71e67137f63632","repo":"apache/beam","slug":"output-from-finishbundle-for-sdf-is-not-supported-in-naive","errorCode":null,"errorMessage":"Output from FinishBundle for SDF is not supported in naive implementation","messagePattern":"Output from FinishBundle for SDF is not supported in naive implementation","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/SplittableParDoNaiveBounded.java","lineNumber":418,"sourceCode":"    }\n\n    @FinishBundle\n    public void finishBundle(FinishBundleContext c) {\n      invoker.invokeFinishBundle(\n          new BaseArgumentProvider<InputT, OutputT>() {\n            @Override\n            public DoFn<InputT, OutputT>.FinishBundleContext finishBundleContext(\n                DoFn<InputT, OutputT> doFn) {\n              return new DoFn<InputT, OutputT>.FinishBundleContext() {\n                @Override\n                public PipelineOptions getPipelineOptions() {\n                  return c.getPipelineOptions();\n                }\n\n                @Override\n                public void output(\n                    @Nullable OutputT output, Instant timestamp, BoundedWindow window) {\n                  throw new UnsupportedOperationException(\n                      \"Output from FinishBundle for SDF is not supported in naive implementation\");\n                }\n\n                @Override\n                public <T> void output(\n                    TupleTag<T> tag, T output, Instant timestamp, BoundedWindow window) {\n                  throw new UnsupportedOperationException(\n                      \"Output from FinishBundle for SDF is not supported in naive implementation\");\n                }\n              };\n            }\n\n            @Override\n            public PipelineOptions pipelineOptions() {\n              return c.getPipelineOptions();\n            }\n\n            @Override","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/util/construction/SplittableParDoNaiveBounded.java#L400-L436","documentation":"SplittableParDoNaiveBounded's FinishBundle output receiver does not support emitting elements when a bundle finishes. The naive SDF implementation only supports output during ProcessElement, so any attempt to emit from finishBundle is rejected. This is an intentional limitation of this portability fallback path.","triggerScenarios":"A DoFn using @FinishBundle that calls c.output(...) while being executed via the naive bounded SDF translation path (e.g. a runner using SplittableParDoNaiveBounded for splittable DoFns).","commonSituations":"Running an SDF pipeline on a runner that falls back to the naive SplittableParDo implementation; a DoFn emits final aggregation results in finishBundle and is accidentally turned into an SDF (e.g. via splittable DoFn annotations or runner translation).","solutions":["Remove the c.output(...) call from the @FinishBundle method and emit elements during @ProcessElement instead","Use a runner/translation that fully supports SDF finishBundle output instead of the naive implementation","Restructure the pipeline so pending outputs are buffered and emitted in the next processElement invocation"],"exampleFix":"// before\n@FinishBundle\npublic void finish(FinishBundleContext c) {\n  c.output(result, timestamp, window); // throws\n}\n// after\n@ProcessElement\npublic void process(ProcessContext c) {\n  emitBuffered(c); // emit only from processElement\n}","handlingStrategy":"validation","validationCode":"if (doFn.getClass().getDeclaredMethodsWithAnnotation(FinishBundle.class).length > 0\n    && finishBundleEmitsOutput(doFn)) {\n  throw new IllegalStateException(\"FinishBundle must not emit output under naive SDF implementation\");\n}","typeGuard":null,"tryCatchPattern":"try { pipeline.run(); } catch (UnsupportedOperationException e) {\n  if (e.getMessage().contains(\"FinishBundle for SDF\")) { /* restructure DoFn to emit in ProcessElement */ }\n  else throw e;\n}","preventionTips":["Never call c.output(...) inside @FinishBundle of a splittable DoFn","Check runner SDF support before relying on finishBundle emissions","Emit pending results at the start of the next @ProcessElement instead"],"tags":["java","beam","sdf","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-14T16:17:12.679Z"}