apache/maven · warning
Illegal call to phase
Error message
Illegal call to phase '{}'. The main phase '{}' will be used instead. What it means
ConcurrentLifecycleStarter.calculateTaskSegments() validates each requested task; isBeforeOrAfterPhase() checks task.startsWith(Lifecycle.BEFORE) or AFTER — the pre-/post- companion phases like pre-clean, post-clean, post-deploy that only exist as hooks inside a full lifecycle. Directly invoking one is illegal, so Maven maps it via PhaseId.of(task).phase() to the main phase and warns that the main phase will be executed instead.
Solutions
- Invoke the main phase instead: 'mvn clean' instead of 'mvn post-clean', 'mvn deploy' instead of 'mvn post-deploy'.
- To run only a hook's bound plugin executions, invoke the plugin goals directly (e.g. 'mvn clean:clean') or bind them to a custom phase.
- Audit build scripts/CI yaml for task names starting with pre-/post- that are lifecycle phases.
Example fix
# before mvn post-clean # warns: Illegal call to phase 'post-clean'. 'clean' used # after mvn clean
Defensive patterns
Strategy: validation
Validate before calling
# guard: reject hook phases (pre-*/post-*) as tasks before invoking Maven
for task in "$@"; do
case "$task" in
pre-*|post-*) echo "illegal direct phase: $task (use the main lifecycle phase)"; exit 2;;
esac
done
mvn "$@" Prevention
- Treat pre-clean/post-clean/pre-site/post-site/post-deploy as hooks, never as standalone goals.
- To execute only hook-bound executions, invoke the specific plugin goals instead of the hook phase.
When it happens
Trigger: Passing a hook phase as a task on the command line or via goals: 'mvn post-clean', 'mvn pre-site', 'mvn post-deploy' — anything starting with 'pre-' or 'post-' that resolves to a lifecycle phase id.
Common situations: Scripts trying to run 'only the cleanup hook' or CI jobs copying phase names from docs; users assuming pre-*/post-* are independently runnable phases; migration from tools where such phases are first-class.
Related errors
- Unknown lifecycle phase
- No goals have been specified for this build. You must…
- The goal you specified requires a project to execute but…
- Unknown lifecycle phase
- -D system property is not set.
AI-assisted analysis of apache/maven@e4093d4e12 (2026-08-21).
Data as JSON: /api/errors/2f1d522683ffcdfe.
Report an issue: GitHub.
Appendix: source
Thrown at impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/ConcurrentLifecycleStarter.java:147
&& !rootProject.getDefaultGoal().isEmpty())) {
tasks = Stream.of(rootProject.getDefaultGoal().split("\\s+"))
.filter(g -> !g.isEmpty())
.collect(Collectors.toList());
}
return calculateTaskSegments(session, tasks);
}
public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks) throws Exception {
List<TaskSegment> taskSegments = new ArrayList<>(tasks.size());
TaskSegment currentSegment = null;
for (String task : tasks) {
if (isBeforeOrAfterPhase(task)) {
String prevTask = task;
task = PhaseId.of(task).phase();
logger.warn("Illegal call to phase '{}'. The main phase '{}' will be used instead.", prevTask, task);
}
if (isGoalSpecification(task)) {
// "pluginPrefix[:version]:goal" or "groupId:artifactId[:version]:goal"
lifecyclePluginResolver.resolveMissingPluginVersions(session.getTopLevelProject(), session);
MojoDescriptor mojoDescriptor =
mojoDescriptorCreator.getMojoDescriptor(task, session, session.getTopLevelProject());
boolean aggregating = mojoDescriptor.isAggregator() || !mojoDescriptor.isProjectRequired();
if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
currentSegment = new TaskSegment(aggregating);
taskSegments.add(currentSegment);
}
currentSegment.getTasks().add(new GoalTask(task));
} else {View on GitHub (pinned to e4093d4e12)