{"record":{"id":"4c4a9dc9a8d4829e","repo":"apache/beam","slug":"the-pipeline-contains-abandoned-passert-s","errorCode":null,"errorMessage":"The pipeline contains abandoned PAssert(s).","messagePattern":"The pipeline contains abandoned PAssert\\(s\\)\\.","errorType":"exception","errorClass":"AbandonedNodeException","httpStatus":null,"severity":"error","filePath":"sdks/java/core/src/main/java/org/apache/beam/sdk/testing/TestPipeline.java","lineNumber":237,"sourceCode":"        return; // this method is to protect against spurious success, so failure is fine\n      }\n\n      final List<TransformHierarchy.Node> runVisitedNodes =\n          checkStateNotNull(\n              this.runVisitedNodes,\n              \"Internal error: non-empty pipeline has been visited but still no runVisitedNodes\");\n      final List<TransformHierarchy.Node> pipelineNodes = recordPipelineNodes(pipeline);\n      if (runVisitedNodes.equals(pipelineNodes)) {\n        return;\n      }\n\n      final boolean hasDanglingPAssert =\n          pipelineNodes.stream()\n              .filter(Predicates.not(Predicates.in(runVisitedNodes)))\n              .anyMatch(isPAssertNode);\n\n      if (hasDanglingPAssert) {\n        throw new AbandonedNodeException(\"The pipeline contains abandoned PAssert(s).\");\n      } else {\n        throw new AbandonedNodeException(\"The pipeline contains abandoned PTransform(s).\");\n      }\n    }\n\n    private boolean pipelineRunSucceeded() {\n      return runVisitedNodes != null;\n    }\n\n    @Override\n    protected void afterPipelineExecution() {\n      runVisitedNodes = recordPipelineNodes(pipeline);\n      super.afterPipelineExecution();\n    }\n\n    @Override\n    protected void afterUserCodeFinished() {\n      super.afterUserCodeFinished();","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/java/core/src/main/java/org/apache/beam/sdk/testing/TestPipeline.java#L219-L255","documentation":"After a run, TestPipeline compares pipeline graph nodes against nodes actually visited during execution. If PAssert nodes exist that were never visited by the run, it throws AbandonedNodeException with this message — meaning some assertions were attached but never evaluated.","triggerScenarios":"PAsserts added to the pipeline after run() was called, or PAsserts applied to a side branch that the runner never executed/visited, with runVisitedNodes not containing them.","commonSituations":"Conditionally adding assertions after run(); attaching PAsserts to outputs of transforms pruned by the runner; building a second pipeline object and asserting on it while running another.","solutions":["Add all PAssert.that(...) calls before invoking pipeline.run().","Verify the PAssert is attached to a PCollection that is part of the executed pipeline (not a detached/unused output).","Re-run the pipeline after adding new assertions."],"exampleFix":"// before\npipeline.run().waitUntilFinish();\nPAssert.that(pcoll).containsInAnyOrder(\"x\");\n// after\nPAssert.that(pcoll).containsInAnyOrder(\"x\");\npipeline.run().waitUntilFinish();","handlingStrategy":"validation","validationCode":"boolean allAssertsBeforeRun = assertsAddedAt < runCalledAt; // enforce asserts precede run()","typeGuard":null,"tryCatchPattern":"try { pipeline.run().waitUntilFinish(); } catch (AbandonedNodeException e) { fail(\"Attach PAsserts before run(): \" + e.getMessage()); }","preventionTips":["Add every PAssert.that(...) before pipeline.run().","Never mutate the pipeline after run().","Assert on PCollections belonging to the executed pipeline graph only."],"tags":["java","testing","apache-beam","assertion"],"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-15T13:17:12.816Z"}