apache/maven · warning
Unexpected skipping of TEARDOWN step {}
Error message
Unexpected skipping of TEARDOWN step {} What it means
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.
Source
Thrown at impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java:461
// Store the exception in the step for handling in the TEARDOWN phase
step.exception = e;
logger.debug("Stored exception for step {} to be handled in TEARDOWN phase", step, e);
// Let the scheduler handle after:* phases and TEARDOWN in the next cycle
executePlan();
}
});
} else if (step.status.compareAndSet(CREATED, SKIPPED)) {
// Skip the step and provide a specific reason
if (!shouldExecute) {
if (status.isHalted()) {
logger.debug("Skipping step {} because the build is halted", step);
} else if (status.isBlackListed(step.project)) {
logger.debug("Skipping step {} because the project is blacklisted", step);
} else if (TEARDOWN.equals(step.name)) {
// This should never happen given we always process TEARDOWN steps
logger.warn("Unexpected skipping of TEARDOWN step {}", step);
} else {
logger.debug("Skipping step {} because a dependency has failed", step);
}
} else {
// Skip because predecessors failed or were skipped
logger.debug(
"Skipping step {} because one or more predecessors did not execute successfully", step);
}
// Recursively call executePlan to process steps that depend on this one
executePlan();
}
}
private void executePlan() {
// Even if the build is halted, we still want to execute TEARDOWN and after:* steps
// for proper cleanup, so we don't return early here
Clock global = getClock(GLOBAL);
global.start();View on GitHub (pinned to e4093d4e12)
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.
Defensive patterns
Strategy: validation
Validate before calling
// embedders: keep TEARDOWN steps always-executable before running the plan
for (Step step : buildPlan.allSteps().toList()) {
if ("TEARDOWN".equals(step.name)) {
assert step.shouldExecute : "TEARDOWN must always execute: " + step;
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Maven core development; third-party builders reusing BuildPlanExecutor with modified plans; effectively unseen in normal CLI builds.
Related errors
- Version not locked for default bindings plugins {}, you shou
- Your build is requesting concurrent execution, but this proj
- The following goals are not Maven 4 goals:
- The following plugins are not Maven 4 plugins:
- Enable verbose output (-X) to see precisely which goals are
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/7c69d0bdf4a80381.
Report an issue: GitHub.