{"record":{"id":"12886afd36e0bbba","repo":"apache/beam","slug":"illegal-access-to-pipeline-after-visitor-traversal-was","errorCode":null,"errorMessage":"Illegal access to pipeline after visitor traversal was completed","messagePattern":"Illegal access to pipeline after visitor traversal was completed","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/Pipeline.java","lineNumber":429,"sourceCode":"     * Control enum for indicating whether or not a traversal should process the contents of a\n     * composite transform or not.\n     */\n    enum CompositeBehavior {\n      ENTER_TRANSFORM,\n      DO_NOT_ENTER_TRANSFORM\n    }\n\n    /**\n     * Default no-op {@link PipelineVisitor} that enters all composite transforms. User\n     * implementations can override just those methods they are interested in.\n     */\n    class Defaults implements PipelineVisitor {\n\n      private @Nullable Pipeline pipeline;\n\n      protected Pipeline getPipeline() {\n        if (pipeline == null) {\n          throw new IllegalStateException(\n              \"Illegal access to pipeline after visitor traversal was completed\");\n        }\n        return pipeline;\n      }\n\n      @Override\n      public void enterPipeline(Pipeline pipeline) {\n        this.pipeline = checkNotNull(pipeline);\n      }\n\n      @Override\n      public CompositeBehavior enterCompositeTransform(TransformHierarchy.Node node) {\n        return CompositeBehavior.ENTER_TRANSFORM;\n      }\n\n      @Override\n      public void leaveCompositeTransform(TransformHierarchy.Node node) {}\n","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/Pipeline.java#L411-L447","documentation":"In Java Beam's Pipeline.Defaults visitor, getPipeline() returns the pipeline captured at the start of traversal. After traversal completes, Defaults clears the reference; any visitor callback (checkForMatches, enterCompositeTransform, visitPrimitiveTransform) invoked afterwards throws this IllegalStateException to prevent mutating a pipeline during/after an already-completed traversal.","triggerScenarios":"Calling Pipeline.traverseTopologically(visitor) a second time with the same Defaults-derived visitor, or invoking visitor callbacks (e.g. a retained visitPrimitiveTransform) after run()/traversal finished.","commonSituations":"Custom PTransform validation tools that reuse a visitor instance across traversals; code that stores the visitor and touches the pipeline after Pipeline.run(); running validate() twice with a stateful visitor.","solutions":["Create a fresh visitor (Defaults subclass) for each traversal instead of reusing one.","Do not invoke visitor methods after Pipeline.run()/traverseTopologically returns; capture needed values during traversal.","If you need post-traversal access, hold a reference to the Pipeline object itself, not via the visitor.","Refactor custom checks to run inside the visit callbacks, not after."],"exampleFix":"// before\n// Defaults v = new MyVisitor(); pipeline.traverseTopologically(v); pipeline.run(); v.enterCompositeTransform(node); // throws\n// after\n// MyVisitor v = new MyVisitor(); pipeline.traverseTopologically(v); // do all inspection inside v's callbacks, before run()","handlingStrategy":"try-catch","validationCode":"// Java: verify the visitor has not been consumed before reusing\nif (visitorUsedOnce) {\n  throw new IllegalStateException('Create a fresh visitor per traversal');\n}","typeGuard":null,"tryCatchPattern":"try {\n  pipeline.traverseTopologically(visitor);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"after visitor traversal was completed\")) {\n    // recreate visitor and re-traverse\n    visitor = new MyVisitor();\n    pipeline.traverseTopologically(visitor);\n  } else { throw e; }\n}","preventionTips":["Instantiate a new visitor for every traversal","Never call visitor callbacks after Pipeline.run() or traverseTopologically returns","Capture pipeline references directly, not through visitor state"],"tags":["java","beam","pipeline","visitor","lifecycle"],"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-14T16:17:12.679Z"}