apache/beam · error · AbandonedNodeException
The pipeline contains abandoned PTransform(s).
Error message
The pipeline contains abandoned PTransform(s).
What it means
Same check as the abandoned PAssert case: if dangling pipeline nodes exist but they are not PAssert nodes, TestPipeline throws AbandonedNodeException stating the pipeline contains abandoned PTransform(s) — transforms present in the graph that the run never visited.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/testing/TestPipeline.java:239
final List<TransformHierarchy.Node> runVisitedNodes =
checkStateNotNull(
this.runVisitedNodes,
"Internal error: non-empty pipeline has been visited but still no runVisitedNodes");
final List<TransformHierarchy.Node> pipelineNodes = recordPipelineNodes(pipeline);
if (runVisitedNodes.equals(pipelineNodes)) {
return;
}
final boolean hasDanglingPAssert =
pipelineNodes.stream()
.filter(Predicates.not(Predicates.in(runVisitedNodes)))
.anyMatch(isPAssertNode);
if (hasDanglingPAssert) {
throw new AbandonedNodeException("The pipeline contains abandoned PAssert(s).");
} else {
throw new AbandonedNodeException("The pipeline contains abandoned PTransform(s).");
}
}
private boolean pipelineRunSucceeded() {
return runVisitedNodes != null;
}
@Override
protected void afterPipelineExecution() {
runVisitedNodes = recordPipelineNodes(pipeline);
super.afterPipelineExecution();
}
@Override
protected void afterUserCodeFinished() {
super.afterUserCodeFinished();
verifyPipelineExecution();
}View on GitHub (pinned to 12126d8942)
Solutions
- Build the complete pipeline graph before calling run(); do not mutate afterwards.
- Ensure each TestPipeline is used by exactly one test and one run (create a fresh TestPipeline per test).
- Check for runner-side pruning if transforms are legitimately unused — restructure so they are connected to a sink or assertion.
Example fix
// before pipeline.run(); result.apply(Count.globally()); // after result.apply(Count.globally()); pipeline.run().waitUntilFinish();
Defensive patterns
Strategy: validation
Validate before calling
if (pipelineFinished) { throw new IllegalStateException("Do not apply transforms to a finished pipeline"); } Try / catch
try { pipeline.run().waitUntilFinish(); } catch (AbandonedNodeException e) { fail("Pipeline graph was mutated after run(): " + e.getMessage()); } Prevention
- Construct the full graph before run(); treat pipelines as immutable afterwards.
- Use a fresh TestPipeline per test method.
- Do not share TestPipeline across threads.
When it happens
Trigger: PTransforms appended to the pipeline graph after run(), or transforms on branches the runner skipped/optimized away, detected by comparing pipelineNodes with runVisitedNodes.
Common situations: Mutating the pipeline after run() in test setup/teardown; constructing pipelines in multiple threads sharing one TestPipeline; applying transforms to a pipeline instance whose run() already completed.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- The pipeline has not been run.
- The pipeline contains abandoned PAssert(s).
- Not expected to access DoFn.StartBundleContext from @Process
- Not expected to access DoFn.FinishBundleContext from @Proces
- Cannot access key as parameter outside of @OnTimer method.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/2889a65debd5452d.
Report an issue: GitHub.