{"record":{"id":"7c69d0bdf4a80381","repo":"apache/maven","slug":"unexpected-skipping-of-teardown-step","errorCode":null,"errorMessage":"Unexpected skipping of TEARDOWN step {}","messagePattern":"Unexpected skipping of TEARDOWN step (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java","lineNumber":461,"sourceCode":"\n                        // Store the exception in the step for handling in the TEARDOWN phase\n                        step.exception = e;\n                        logger.debug(\"Stored exception for step {} to be handled in TEARDOWN phase\", step, e);\n\n                        // Let the scheduler handle after:* phases and TEARDOWN in the next cycle\n                        executePlan();\n                    }\n                });\n            } else if (step.status.compareAndSet(CREATED, SKIPPED)) {\n                // Skip the step and provide a specific reason\n                if (!shouldExecute) {\n                    if (status.isHalted()) {\n                        logger.debug(\"Skipping step {} because the build is halted\", step);\n                    } else if (status.isBlackListed(step.project)) {\n                        logger.debug(\"Skipping step {} because the project is blacklisted\", step);\n                    } else if (TEARDOWN.equals(step.name)) {\n                        // This should never happen given we always process TEARDOWN steps\n                        logger.warn(\"Unexpected skipping of TEARDOWN step {}\", step);\n                    } else {\n                        logger.debug(\"Skipping step {} because a dependency has failed\", step);\n                    }\n                } else {\n                    // Skip because predecessors failed or were skipped\n                    logger.debug(\n                            \"Skipping step {} because one or more predecessors did not execute successfully\", step);\n                }\n                // Recursively call executePlan to process steps that depend on this one\n                executePlan();\n            }\n        }\n\n        private void executePlan() {\n            // Even if the build is halted, we still want to execute TEARDOWN and after:* steps\n            // for proper cleanup, so we don't return early here\n            Clock global = getClock(GLOBAL);\n            global.start();","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/apache/maven/blob/e4093d4e120eac99d6bdce5ba67cace2f3085c97/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java#L443-L479","documentation":"Internal invariant warning in BuildPlanExecutor.executePlan(): steps that cannot run are transitioned CREATED->SKIPPED with a reason; the code asserts TEARDOWN steps are always processed, so hitting the TEARDOWN branch ('Unexpected skipping of TEARDOWN step') means the executor's own invariant was violated — e.g. a TEARDOWN step whose shouldExecute was false while the build was neither halted nor the project blacklisted. It signals a bug or unexpected state in the concurrent build plan, not user misconfiguration.","triggerScenarios":"Embedding/extending Maven 4's concurrent BuildPlanExecutor with a custom BuildPlan or status (halt/blacklist flags manipulated externally) such that a TEARDOWN step lands in the skip path; races between status.isHalted()/isBlackListed() transitions and step scheduling.","commonSituations":"Maven core development; third-party builders reusing BuildPlanExecutor with modified plans; effectively unseen in normal CLI builds.","solutions":["Report it as an Apache Maven issue with the full -X log and build plan if it occurs with stock Maven.","If you embed BuildPlanExecutor, ensure TEARDOWN steps always have shouldExecute == true and that halt/blacklist state changes cannot race step CAS transitions.","Re-run single-threaded to confirm the build itself is fine; the warning does not necessarily fail the build."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// embedders: keep TEARDOWN steps always-executable before running the plan\nfor (Step step : buildPlan.allSteps().toList()) {\n    if (\"TEARDOWN\".equals(step.name)) {\n        assert step.shouldExecute : \"TEARDOWN must always execute: \" + step;\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not mutate Status halted/blacklist state concurrently with step scheduling when embedding the executor.","If seen with stock Maven, capture -X logs and the reactor order and file a Maven issue."],"tags":["maven","maven-4","concurrent-build","internal-invariant","build-plan"],"backgroundTag":"maven-build-step-skipped","analyzedSha":"e4093d4e120eac99d6bdce5ba67cace2f3085c97","analyzedAt":"2026-08-21T22:58:24.034Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}